fix(mcp): daemon stop closes pending sockets; a blocked fallback serves reads (#1963) - #1979
danusha2345 wants to merge 2 commits into
Conversation
|
Thanks, go ahead with yours. I compared it with what our fork runs and the behavior matches: stop destroys pending sockets and drops connections that arrive mid-stop, and the fallback serves reads with no lock and no watcher, while the unreadable-lock and legacy-daemon refusals stay. I won't open a competing PR. One optional extra: our fork writes a line to stderr when it falls back to read-only, e.g. |
…henry#1963) A read-only fallback starts no watcher and holds no writer lock, so a session that quietly stopped syncing looked the same as a healthy one in the logs. Name the holder on stderr when the fallback goes read-only. Suggested by @bompus in colbymchenry#1979. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks for checking it against your fork. Added the stderr line in 364d379: a read-only fallback now logs |
…henry#1963) A read-only fallback starts no watcher and holds no writer lock, so a session that quietly stopped syncing looked the same as a healthy one in the logs. Name the holder on stderr when the fallback goes read-only. Suggested by @bompus in colbymchenry#1979. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…) (#2042) * fix(mcp): close pending sockets and allow read-only fallback (#1963) * fix(mcp): log when a fallback serves reads without auto-sync (#1963) A read-only fallback starts no watcher and holds no writer lock, so a session that quietly stopped syncing looked the same as a healthy one in the logs. Name the holder on stderr when the fallback goes read-only. Suggested by @bompus in #1979. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(mcp): stop pending connections and serve read-only fallbacks (#1963) Pending handshakes could block daemon shutdown or register phantom sessions after disconnect. Track accepted sockets and reject late hello continuations. Use explicit read-only engines and SQLite connections for blocked fallbacks, suppressing synchronization, watching, migrations, and repairs. Preserve writer ownership and the existing project lifecycle, with regression coverage for #1963 and #1356. Co-authored-by: danusha2345 <danusha2345@users.noreply.github.com> Co-authored-by: danusha2345 <ewidusoc498@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: danusha2345 <danusha2345@users.noreply.github.com> Co-authored-by: danusha2345 <ewidusoc498@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks @danusha2345! Your commits here were carried into #2042 (authorship preserved), with a few follow-up changes from review, and that is now merged. Closing this one in favour of it. It will be in the next release. |
Fixes #1963. This implements the two changes @bompus proposed in the issue.
Problem
Daemon.stop()can hang. A launcher that connects just as the daemon starts stopping is accepted, but it only joinsclientsafter its client hello.stop()closes the sessions inclients, then awaitsserver.close(), which waits on that unregistered socket. The daemon keepswriter.pidwhile its socket is already unusable.makeFallbackEnginethrows "writer lock held". The same happens on a daemon version mismatch, and when another session's fallback holds the lock, so one fallback locks every later session out of CodeGraph.Fix
Daemontracks every accepted socket, destroys new connections that arrive while it is stopping, and destroys all tracked sockets beforeserver.close(). A hello that resolves after stop began no longer creates a session.new MCPEngine({ watch: false }). It serves reads from the WAL database, starts no watcher and claims no lock. The unreadable-lock and legacy-daemon refusals are unchanged.Tests
mcp-daemon.test.ts:codegraph_statusanswer, and still check that nowriter.pidwas claimed.Full suite on this branch (Linux, Node 22, native kernel): all tests pass except the known
extraction.test.tspool-worker crash from #1779 (fixed by #1883), which is intermittent and also occurs onmain; that file alone passes 655/655.🤖 Generated with Claude Code