diff --git a/src/daemon/launchd-plist.ts b/src/daemon/launchd-plist.ts index a9b489af438..19c0447da45 100644 --- a/src/daemon/launchd-plist.ts +++ b/src/daemon/launchd-plist.ts @@ -1,8 +1,8 @@ import fs from "node:fs/promises"; // launchd applies ThrottleInterval to any rapid relaunch, including config-crash -// loops. Intentional gateway restarts use launchctl kickstart, so a higher value -// here primarily slows unhealthy restart storms without making operator restarts sluggish. +// loops and clean supervised exits. Keep KeepAlive=true so intentional restarts +// still come back up, and use a higher throttle to slow unhealthy restart storms. export const LAUNCH_AGENT_THROTTLE_INTERVAL_SECONDS = 30; // launchd stores plist integer values in decimal; 0o077 renders as 63 (owner-only files). export const LAUNCH_AGENT_UMASK_DECIMAL = 0o077; @@ -113,5 +113,5 @@ export function buildLaunchAgentPlist({ ? `\n Comment\n ${plistEscape(comment.trim())}` : ""; const envXml = renderEnvDict(environment); - return `\n\n\n \n Label\n ${plistEscape(label)}\n ${commentXml}\n RunAtLoad\n \n KeepAlive\n \n SuccessfulExit\n \n \n ThrottleInterval\n ${LAUNCH_AGENT_THROTTLE_INTERVAL_SECONDS}\n Umask\n ${LAUNCH_AGENT_UMASK_DECIMAL}\n ProgramArguments\n ${argsXml}\n \n ${workingDirXml}\n StandardOutPath\n ${plistEscape(stdoutPath)}\n StandardErrorPath\n ${plistEscape(stderrPath)}${envXml}\n \n\n`; + return `\n\n\n \n Label\n ${plistEscape(label)}\n ${commentXml}\n RunAtLoad\n \n KeepAlive\n \n ThrottleInterval\n ${LAUNCH_AGENT_THROTTLE_INTERVAL_SECONDS}\n Umask\n ${LAUNCH_AGENT_UMASK_DECIMAL}\n ProgramArguments\n ${argsXml}\n \n ${workingDirXml}\n StandardOutPath\n ${plistEscape(stdoutPath)}\n StandardErrorPath\n ${plistEscape(stderrPath)}${envXml}\n \n\n`; } diff --git a/src/daemon/launchd.test.ts b/src/daemon/launchd.test.ts index f1b7574eb46..a10d254b3c7 100644 --- a/src/daemon/launchd.test.ts +++ b/src/daemon/launchd.test.ts @@ -189,7 +189,7 @@ describe("launchd install", () => { expect(plist).toContain(`${tmpDir}`); }); - it("writes KeepAlive restart-on-failure policy with restrictive umask", async () => { + it("writes KeepAlive policy with restrictive umask", async () => { const env = createDefaultLaunchdEnv(); await installLaunchAgent({ env, @@ -200,9 +200,7 @@ describe("launchd install", () => { const plistPath = resolveLaunchAgentPlistPath(env); const plist = state.files.get(plistPath) ?? ""; expect(plist).toContain("KeepAlive"); - expect(plist).toContain(""); - expect(plist).toContain("SuccessfulExit"); - expect(plist).toContain(""); + expect(plist).toContain(""); expect(plist).toContain("Umask"); expect(plist).toContain(`${LAUNCH_AGENT_UMASK_DECIMAL}`); expect(plist).toContain("ThrottleInterval");