diff --git a/apps/server/src/cloud/bootService.test.ts b/apps/server/src/cloud/bootService.test.ts index 12eebbbd223..b86f6b43893 100644 --- a/apps/server/src/cloud/bootService.test.ts +++ b/apps/server/src/cloud/bootService.test.ts @@ -35,6 +35,18 @@ it("keeps systemd pinned to the stable launcher rather than a versioned server", expect(unit).not.toContain("versions/1.2.3"); }); +it("survives the kernel OOM-killing a greedy agent child", () => { + const unit = BootService.renderBootServiceUnit({ + nodePath: "/usr/bin/node", + launcherPath: "/home/theo/.t3/runtime/service-launcher.mjs", + baseDir: "/home/theo/.t3", + logPath: "/home/theo/.t3/userdata/logs/boot-service.log", + unitPath: "/home/theo/.config/systemd/user/t3code.service", + }); + + expect(unit).toContain("OOMPolicy=continue"); +}); + const makeHarness = Effect.fn("test.make_boot_service_harness")(function* ( platform: NodeJS.Platform = "linux", usePinnedLauncher = false, diff --git a/apps/server/src/cloud/bootService.ts b/apps/server/src/cloud/bootService.ts index a57585be4b2..7eef6feba50 100644 --- a/apps/server/src/cloud/bootService.ts +++ b/apps/server/src/cloud/bootService.ts @@ -67,6 +67,11 @@ export function renderBootServiceUnit(plan: BootServicePlan): string { // Let the launcher mark an explicit stop before it signals the server. // systemd still SIGKILLs the whole cgroup if graceful shutdown times out. "KillMode=mixed", + // Agent tool calls run as children of the server, so they share this cgroup. + // With the systemd default of OOMPolicy=stop, the kernel killing one greedy + // child stops the whole unit: the server, every live agent, and the user's + // connection. Keep running and let Restart=always cover the main process. + "OOMPolicy=continue", "Restart=always", "RestartSec=5", `StandardOutput=append:${escapeSystemdSpecifiers(plan.logPath)}`,