fix(runner): contain remote signal failures after sandbox deletion
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
parent
8279608917
commit
cb938e4006
|
|
@ -291,7 +291,8 @@ beforeEach(() => {
|
|||
});
|
||||
|
||||
describe("remote runner process supervision", () => {
|
||||
it("detaches runnerd from the provider RPC and monitors its durable identity", async () => {
|
||||
it.each(["delivered", "sandbox_missing", "logging_failed"] as const)(
|
||||
"detaches runnerd and contains asynchronous signal failures (%s)", async (signalOutcome) => {
|
||||
let launchNonce = "";
|
||||
const execute = vi.fn(
|
||||
async (input: {
|
||||
|
|
@ -354,6 +355,7 @@ describe("remote runner process supervision", () => {
|
|||
};
|
||||
}
|
||||
if (label === "paperclip-runner-signal") {
|
||||
if (signalOutcome !== "delivered") throw new Error("Sandbox with ID test-deleted-sandbox not found");
|
||||
return {
|
||||
exitCode: 0,
|
||||
signal: null,
|
||||
|
|
@ -366,6 +368,9 @@ describe("remote runner process supervision", () => {
|
|||
},
|
||||
);
|
||||
const onSpawn = vi.fn(async () => undefined);
|
||||
const onLog = vi.fn(async () => {
|
||||
if (signalOutcome === "logging_failed") throw new Error("Run log already closed");
|
||||
});
|
||||
const launcher = createRemoteRunnerProcessLauncher({
|
||||
target: {
|
||||
kind: "remote",
|
||||
|
|
@ -381,6 +386,7 @@ describe("remote runner process supervision", () => {
|
|||
diagnosticsDirectory: "/runtime/diagnostics",
|
||||
runnerInstanceId: "runner-remote",
|
||||
onSpawn,
|
||||
onLog,
|
||||
});
|
||||
|
||||
const handle = launcher({
|
||||
|
|
@ -424,6 +430,17 @@ describe("remote runner process supervision", () => {
|
|||
),
|
||||
).toBe(true),
|
||||
);
|
||||
if (signalOutcome !== "delivered") {
|
||||
await vi.waitFor(() => expect(onLog).toHaveBeenCalledWith(
|
||||
"stderr", "Remote runner signal failed; process termination is not confirmed.\n",
|
||||
));
|
||||
// Let rejected logging callbacks settle too. Neither failure may escape
|
||||
// this fire-and-forget Node child-process-compatible kill boundary.
|
||||
await new Promise<void>((resolve) => setImmediate(resolve));
|
||||
} else {
|
||||
expect(onLog).not.toHaveBeenCalled();
|
||||
}
|
||||
expect(handle.child.exitCode).toBeNull();
|
||||
});
|
||||
|
||||
it("terminates a detached runner when its process identity cannot be adopted", async () => {
|
||||
|
|
|
|||
|
|
@ -9593,7 +9593,16 @@ export function createRemoteRunnerProcessLauncher(input: {
|
|||
],
|
||||
bypassSession: true,
|
||||
timeoutMs: 10_000,
|
||||
});
|
||||
}).catch(async () => {
|
||||
// kill() follows Node's synchronous child-process contract. A deleted
|
||||
// sandbox or failed signal RPC must not reject outside that boundary
|
||||
// and crash the controller. This is not a termination receipt: the
|
||||
// monitor and cleanup verification still decide whether work stopped.
|
||||
await input.onLog?.(
|
||||
"stderr",
|
||||
"Remote runner signal failed; process termination is not confirmed.\n",
|
||||
);
|
||||
}).catch(() => undefined);
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue