fix(gateway): exit cleanly when another instance detected to avoid launchd restart loop - #21555
liuhao1024 wants to merge 1 commit into
Conversation
…unchd restart loop When launchd (macOS) spawns two gateway instances simultaneously, the second instance detects the first via PID file and exits with code 1. With KeepAlive.SuccessfulExit=false, launchd interprets exit code 1 as a failure and immediately restarts, creating an infinite loop. Change all duplicate-instance guard paths to return True (exit 0) since detecting another healthy instance is not a failure. This matches the semantics expected by both launchd (SuccessfulExit=false) and systemd (Restestart=on-failure). Also downgrade logger.error to logger.warning for these paths since the situation is expected during race conditions, not an error. Fixes NousResearch#21549
|
This PR addresses the macOS launchd double-spawn scenario, but the same root cause Environment: WSL2 Ubuntu 24.04, hermes-gateway.service with Scenario: When Evidence from journalctl: The restart counter reached 76 within hours. Suggestion: In addition to the This ensures the port is freed before the new process starts, covering cases The code fix in this PR should prevent the exit-1 loop. The ExecStartPre is a |
|
Closing — the exit-code premise this builds on has been reworked on Premise is stale. When this PR was filed (May 7), the concern was "duplicate-instance guard exits 1 →
No corroborating reports. Across the entire launchd/KeepAlive/SuccessfulExit issue history, #21549 is the only report of this specific failure (second instance detects first via PID file → exit 1 → loop), and it was never reliably reproduced ("Hard to reproduce reliably… depends on launchd timing"). The other launchd crash-loops on the tracker are distinct root causes (root-owned lock, missing bootout, EX_CONFIG 78, on-demand-only deferral, etc.). The real, confirmed double-spawn cause is tracked separately. #42446 (independently reported) → #42450 identifies Flipping all four duplicate-instance guards to Thanks for the detailed writeup and tests — the analysis was genuinely useful for confirming the area was already addressed. Closing #21549 alongside this. |
What does this PR do?
When
launchd(macOS) spawns two gateway instances simultaneously (e.g., during display wake orKeepAliverestart), the second instance detects the first via PID file and exits with code 1 (return False→sys.exit(1)). WithKeepAlive.SuccessfulExit=false, launchd interprets exit code 1 as a failure and immediately restarts — creating an infinite restart loop that spams logs and drains CPU.Root Cause
start_gateway()has multiple duplicate-instance guard paths thatreturn Falsewhen another instance is detected:get_running_pid()finds an existing instance (line ~15145)acquire_gateway_runtime_lock()fails (line ~15297)write_pid_file()raisesFileExistsError(line ~15303)All four paths call
return False, which causessys.exit(1)in the caller. This is correct behavior for actual failures (no platforms connected, etc.), but wrong for "another instance is already running" — that's a clean exit, not a failure.Related Issue
Fixes #21549
Type of Change
Changes Made
How to Test
pytest tests/ -q— all tests should passChecklist
Code
fix(scope):,feat(scope):, etc.)pytest tests/ -qand all tests passDocumentation & Housekeeping
docs/, docstrings) — or N/Acli-config.yaml.exampleif I added/changed config keys — or N/ACONTRIBUTING.mdorAGENTS.mdif I changed architecture and workflows — or N/A