emrg: daemon single-instance via fixed-port bind exclusivity (rant 2026-08-19T08:05:21) - #861
Merged
Merged
Conversation
added 3 commits
August 19, 2026 08:22
…try (SO_REUSEADDR is mutually exclusive, WSAEINVAL)
argszero
commented
Aug 19, 2026
OwnerAuthor
Update (post CI-failure discovery): the first CI run caught a Windows-only problem — The rant's intent (fast TIME_WAIT restart and no port hijacking) is preserved with a different mechanism:
Acceptance mapping still holds: two daemons → one survives; crash-restart has no unbounded TIME_WAIT stall; no file operation can start a second daemon. |
Uh oh!
There was an error while loading. Please reload this page.
This was referenced Aug 19, 2026
emrg: auto-upgrade refactor — agent-driven local equivalent install replaces installer download
#882
Merged
Merged
argszero added a commit
that referenced
this pull request
Aug 21, 2026
…rt (fixed-port admission regression) (#906) Since #861 (rant 2026-08-19T08:05:21) the daemon binds a FIXED loopback port (56031) as its single-instance admission, and #884 (rant 2026-08-20T14:32:52) moved the auth credential to emrgd.token (port no longer carried in any file). The GUI integration suite spawns its OWN isolated daemon (HOME->tmp) — on any host where the real daemon is already running (the normal dev-machine state), the isolated daemon cannot bind 56031 (EADDRINUSE) and exits, so every test times out with "daemon token file timeout" (7 failures on ). CI stays green only because runners have no live daemon. Fix: probe 127.0.0.1:56031 at module load; when a live daemon already owns the fixed port, skip the whole suite with a clear message (same mechanism as EMRG_SKIP_INTEGRATION, extended to the live-daemon state — the isolated-daemon premise is impossible there). CI (daemon-free runners) still runs the full suite. Also sync Agent.md GUI test count: 260 -> 254 (renderer.smoke 131->126, i18n 16->15 drifted in #896-#905 without doc re-sync; the doc-count guard only checks breakdown-sum consistency, not actual collection). Verified: pytest 984+1 green, GUI 247 pass / 0 fail (8 skipped on this daemon-hosting host), import + --help OK.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Host rant 2026-08-19T08:05:21: the daemon's PID-file single-instance admission is unreliable — multiple daemons have coexisted (4 instances on 08-18; dual instances PID 3924+2592 on 08-19, caused by a stale
os.kill(pid,0)liveness probe). Root cause:serve()binds a random port (port=0), so kernel port exclusivity can never engage, andemrgd.pidis a plain file whose content can be overwritten/deleted.This PR makes the fixed-port bind the only single-instance admission (rant: "唯一机制,无需任何其他兜底"):
emrg/server/daemon.py):serve()now pre-creates a listening socket on the fixed127.0.0.1:56031(EMRGD_PORT). A second bind fails withEADDRINUSE→ logsemrgd already running ... fixed-port admissionand exits itself. Pure kernel resource exclusivity: nothing to forge, no race window, auto-released on crash.SO_EXCLUSIVEADDRUSE+SO_REUSEADDRtogether (fast TIME_WAIT restart and no port hijacking —SO_REUSEADDRalone would allow any socket to steal the port).SO_REUSEADDRonly (fast restart; two listeners still impossible —SO_REUSEPORTdeliberately never set).emrgd.pidis demoted to diagnostics only — written after a successful bind, never used as an admission gate. The old process-name scan (_find_emrg_server_processes), port-file liveness probe, and O_EXCL pid-file admission are all removed (the rant explicitly replaces them: "升级后即唯一生效").emrg/connect.py):EMRGD_PORT = 56031constant.connect_to_server()reads only the auth token fromemrgd.portand connects to the fixed port;is_server_running_sync()probes the fixed port directly (no file read — a missing/stale port file can no longer hide a live daemon, the exact dual-instance root cause).daemon_manager.pyinherits both via delegation (no change needed).emrg/_stop_all.py, pure stdlib):_EMRGD_PORT = 56031(kept in sync by comment);stop_daemon()sends the graceful WS shutdown to the fixed port with the token read fromemrgd.port.test_ws_e2eboots on a free patched port so tests never fight a real daemon. Agent.md count synced.Acceptance (rant)
emrgd already runningand exits. ✅ (bind exclusivity, verified with real sockets)Verification
serve()admission paths (mocked bind): EADDRINUSE →_running=False, no pid, websockets serve not reached; free port → pid diagnostic written, serve reached; EACCES → propagated._stop_all.stop_daemon()against a stub WS server: token read from port file, gracefulshutdownsent to the fixed port.