Skip to content

fix(desktop): reap stale gateway orphans on Desktop backend startup - #78002

Closed
JoaoMarcos44 wants to merge 1 commit into
NousResearch:mainfrom
JoaoMarcos44:fix/77276-desktop-gateway-orphan-reap
Closed

fix(desktop): reap stale gateway orphans on Desktop backend startup#78002
JoaoMarcos44 wants to merge 1 commit into
NousResearch:mainfrom
JoaoMarcos44:fix/77276-desktop-gateway-orphan-reap

Conversation

@JoaoMarcos44

@JoaoMarcos44 JoaoMarcos44 commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Fixes #77276

Summary

Desktop restarts can leave a gateway process orphaned on hosts without a service supervisor (WSL, no-systemd Linux, some Windows setups), causing a duplicate gateway to run alongside the freshly-started one — which splits or duplicates inbound messages on connected platforms (QQ, Discord, etc.).

Root cause

Desktop tears down the previous backend two ways, neither of which reaches a detached gateway:

  • POSIX: a plain SIGTERM to the backend's direct child only (apps/desktop/electron/backend-child.ts) — deliberately, since the backend itself isn't spawned detached and there's no process group to negative-PID-kill.
  • Windows: a full process-tree kill (taskkill /T /F).

But the actual gateway daemon is spawned via hermes gateway restart, which detaches into its own session (start_new_session=True / Windows detach flags) specifically so it does survive backend churn intentionally for one-shot maintenance actions (backup, hermes-update, doctor, etc.). That same detachment means a plain SIGTERM never reaches it — and on hosts without a supervisor watching the gateway's lifecycle, the old instance just keeps running after the new backend starts and spawns its own.

I first considered patching _lifespan's shutdown to terminate() everything tracked in _ACTION_PROCS. Rejected: that dict also tracks legitimate one-shot actions that are supposed to outlive a backend restart (backup, hermes-update, doctor, skills-install...) — a blanket kill would corrupt in-flight backups/updates, trading one bug for a worse one.

Fix

hermes_cli/gateway.py already has _reap_unsupervised_gateway_orphans() — built and tested for the exact same failure mode on the CLI restart path (#51325, #75936), including the supports_systemd_services() gate so it's a no-op wherever a real supervisor already owns the gateway's lifecycle. This PR calls it once, on Desktop backend startup, before the new backend can spawn its own gateway — closing the Desktop-restart gap with already-proven logic instead of inventing new kill paths.

Test plan

  • test_startup_reaps_gateway_orphans_when_desktop — sweep runs when HERMES_DESKTOP=1
  • test_startup_skips_gateway_reap_when_not_desktop — server-mode backend does not run the desktop-only sweep
  • tests/hermes_cli/test_web_server.py full suite: 134 passed, 5 skipped
  • tests/hermes_cli/test_gateway.py full suite: 10 passed, 5 skipped (no regression on the reused reaper)
%%{init: {'theme': 'dark', 'themeVariables': { 'primaryColor': '#8b0000', 'mainBkg': '#0a0204', 'primaryTextColor': '#ffccd5', 'primaryBorderColor': '#ff0038', 'lineColor': '#ff0038'}}}%%
graph TD
    A[🩸 Desktop Restart] -->|POSIX SIGTERM / Win taskkill /T| B[⚰️ Old Backend Dies]
    C[🔥 Detached Gateway Session] -->|start_new_session=True| D[👻 Survives As Orphan]
    B --> D
    D --> E{New Backend Boots}
    E -->|HERMES_DESKTOP=1| F[⚔️ _reap_stale_desktop_gateway_orphans]
    F -->|Reuses #51325/#75936 Reaper| G[🕯️ Orphan Exorcised Before Fresh Gateway Spawns]
Loading

Infographic :

infographic

Desktop tears down the previous backend with a plain SIGTERM on POSIX
or a full process-tree kill on Windows (backend-child.ts). Neither
path reaches a gateway spawned via `hermes gateway restart`, which
detaches into its own session (start_new_session=True). On hosts
without a service supervisor this stacked a duplicate, unsupervised
gateway on every Desktop restart, splitting/duplicating inbound
messages on connected platforms.

_reap_unsupervised_gateway_orphans already solves this exact class of
bug for the CLI restart path (NousResearch#51325, NousResearch#75936), including the
systemd-aware no-op gate. Reuses it on Desktop backend startup instead
of adding new kill logic or terminating _ACTION_PROCS generically
(which would have killed legitimate one-shot actions like backup and
hermes-update that are meant to survive a backend restart).

Fixes NousResearch#77276
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/cli CLI entry point, hermes_cli/, setup wizard needs-decision Awaiting maintainer decision before any implementation labels Aug 3, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Related: #77721 also fixes #77276 using _reap_unsupervised_gateway_orphans() but invokes it from the restart path; this PR invokes it during desktop backend startup. These overlap but have different lifecycle coverage, so they need a maintainer consolidation choice.

@teknium1

Copy link
Copy Markdown
Contributor

Resolved on main — and a credit correction is owed here: you submitted this startup-path reap on Aug 3, a day before #78312 (merged via #83406), making you the earliest submitter of this fix. Our duplicate sweep missed this PR at salvage time; apologies for that. Noting for the record that the design (reuse _reap_unsupervised_gateway_orphans in the Desktop lifespan under HERMES_DESKTOP=1, keeping the systemd no-op gate) was submitted here first.

The merged implementation is functionally equivalent to yours; #83542 additionally covered the restart path and shutdown termination. Thank you for the contribution and the clear analysis of the detached-session gap in your PR body.

@teknium1 teknium1 closed this Aug 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard needs-decision Awaiting maintainer decision before any implementation P2 Medium — degraded but workaround exists type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Desktop app restart leaves orphan gateway (app-managed spawn path not covered by #75936 fix)

3 participants