mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-12 16:41:10 +00:00
fix: detect OpenClaw-managed launchd/systemd services in process respawn
restartGatewayProcessWithFreshPid() checks SUPERVISOR_HINT_ENV_VARS to decide whether to let the supervisor handle the restart (mode=supervised) or to fork a detached child (mode=spawned). The existing list only had native launchd vars (LAUNCH_JOB_LABEL, LAUNCH_JOB_NAME) and systemd vars (INVOCATION_ID, SYSTEMD_EXEC_PID, JOURNAL_STREAM). macOS launchd does NOT automatically inject LAUNCH_JOB_LABEL into the child environment. OpenClaw's own plist generator (buildServiceEnvironment in service-env.ts) sets OPENCLAW_LAUNCHD_LABEL instead. So on stock macOS LaunchAgent installs, isLikelySupervisedProcess() returned false, causing the gateway to fork a detached child on SIGUSR1 restart. The original process then exits, launchd sees its child died, respawns a new instance which finds the orphan holding the port — infinite crash loop. Fix: add OPENCLAW_LAUNCHD_LABEL, OPENCLAW_SYSTEMD_UNIT, and OPENCLAW_SERVICE_MARKER to the supervisor hint list. These are set by OpenClaw's own service environment builders for both launchd and systemd and are the reliable supervised-mode signals. Fixes #27605
This commit is contained in:
committed by
Peter Steinberger
parent
5c0255477c
commit
792ce7b5b4
@@ -23,9 +23,12 @@ afterEach(() => {
|
||||
function clearSupervisorHints() {
|
||||
delete process.env.LAUNCH_JOB_LABEL;
|
||||
delete process.env.LAUNCH_JOB_NAME;
|
||||
delete process.env.OPENCLAW_LAUNCHD_LABEL;
|
||||
delete process.env.INVOCATION_ID;
|
||||
delete process.env.SYSTEMD_EXEC_PID;
|
||||
delete process.env.JOURNAL_STREAM;
|
||||
delete process.env.OPENCLAW_SYSTEMD_UNIT;
|
||||
delete process.env.OPENCLAW_SERVICE_MARKER;
|
||||
}
|
||||
|
||||
describe("restartGatewayProcessWithFreshPid", () => {
|
||||
@@ -63,6 +66,30 @@ describe("restartGatewayProcessWithFreshPid", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("returns supervised when OPENCLAW_LAUNCHD_LABEL is set (stock launchd plist)", () => {
|
||||
clearSupervisorHints();
|
||||
process.env.OPENCLAW_LAUNCHD_LABEL = "ai.openclaw.gateway";
|
||||
const result = restartGatewayProcessWithFreshPid();
|
||||
expect(result.mode).toBe("supervised");
|
||||
expect(spawnMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("returns supervised when OPENCLAW_SYSTEMD_UNIT is set", () => {
|
||||
clearSupervisorHints();
|
||||
process.env.OPENCLAW_SYSTEMD_UNIT = "openclaw-gateway.service";
|
||||
const result = restartGatewayProcessWithFreshPid();
|
||||
expect(result.mode).toBe("supervised");
|
||||
expect(spawnMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("returns supervised when OPENCLAW_SERVICE_MARKER is set", () => {
|
||||
clearSupervisorHints();
|
||||
process.env.OPENCLAW_SERVICE_MARKER = "gateway";
|
||||
const result = restartGatewayProcessWithFreshPid();
|
||||
expect(result.mode).toBe("supervised");
|
||||
expect(spawnMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("returns failed when spawn throws", () => {
|
||||
delete process.env.OPENCLAW_NO_RESPAWN;
|
||||
clearSupervisorHints();
|
||||
|
||||
Reference in New Issue
Block a user