Skip to content

fix: prevent systemd restart loop from stale/colliding PID files - #582

Closed
Bartok9 wants to merge 1 commit into
NousResearch:mainfrom
Bartok9:fix/systemd-pid-lock-robustness
Closed

fix: prevent systemd restart loop from stale/colliding PID files#582
Bartok9 wants to merge 1 commit into
NousResearch:mainfrom
Bartok9:fix/systemd-pid-lock-robustness

Conversation

@Bartok9

@Bartok9 Bartok9 commented Mar 7, 2026

Copy link
Copy Markdown
Contributor

Fixes #576

Problem

When Hermes is run under systemd, the service can enter restart loops due to:

  1. Stale PID files: If the gateway crashes without cleanup (e.g., SIGKILL), the PID file remains
  2. PID collision: A different process may reuse the same PID number, causing false "Gateway already running" errors

Solution

1. Robust PID verification

Enhanced get_running_pid() to verify the process is actually a hermes gateway, not just any process with that PID. The new _is_hermes_gateway_process() helper:

  • On Linux: checks /proc/{pid}/cmdline directly (fast, no subprocess)
  • On macOS: uses ps command

2. Added --replace flag

New hermes gateway run --replace option that:

  • Terminates any existing gateway gracefully
  • Cleans up stale PID files
  • Enables idempotent startup for service managers

3. Improved service templates

systemd unit:

  • Uses --replace by default
  • Added ExecStop for clean shutdown
  • Added StartLimitIntervalSec/StartLimitBurst to prevent aggressive restart loops
  • Changed After=network.target to After=network-online.target
  • Set RestartSec=15 (was 10)
  • Explicitly sets HERMES_HOME environment variable

launchd plist:

  • Uses --replace by default
  • Added ThrottleInterval=15
  • Explicitly sets HERMES_HOME environment variable

4. Better error messages

When duplicate instance is detected, the error message now suggests:

  • hermes gateway run --replace for force takeover
  • hermes gateway install --force for service reinstallation

Testing

Added tests/gateway/test_status.py with tests for:

  • Nonexistent PID handling
  • Stale PID file cleanup
  • PID collision detection (core fix)
  • Basic write/remove operations

All tests pass.

For users experiencing this issue

After updating, reinstall the service to get the new template:

hermes gateway install --force
hermes gateway start

Or manually start with:

hermes gateway run --replace

Fixes NousResearch#576

This PR addresses the systemd restart loop issue caused by:
1. Stale PID files left behind after gateway crash (SIGKILL)
2. PID collision when a different process reuses the same PID number

Changes:
- Enhanced get_running_pid() to verify the process is actually a hermes
  gateway, not just any process with that PID
- Added _is_hermes_gateway_process() helper that checks /proc/{pid}/cmdline
  on Linux and uses 'ps' on macOS
- Added --replace flag for 'hermes gateway run' to force takeover of
  existing PID locks
- Updated systemd unit template to use --replace for idempotent startup
- Updated launchd plist template similarly
- Added StartLimitIntervalSec/StartLimitBurst to prevent aggressive
  restart loops
- Added ExecStop directive for cleaner service shutdown
- Added tests for PID file handling

The key insight: when checking if a gateway is already running, we now
verify both that the PID exists AND that it's actually a hermes gateway
process. This prevents false positives from PID reuse after crashes.
@teknium1

teknium1 commented Mar 8, 2026

Copy link
Copy Markdown
Contributor

Fixed via PR #614 (39ee351) which adds a --replace flag with proper SIGTERM→SIGKILL escalation. Your PID collision detection idea is solid defense-in-depth — we may revisit that as a follow-up. Thanks @Bartok9!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: systemd restart loop (non-TTY CLI exit and "gateway already running" conflict)

2 participants