Skip to content

fix(rpc): publish close after registry removal and join watcher shutdown - #1702

Merged
code-yeongyu merged 3 commits into
mainfrom
fix/rpc-close-ordering-and-watcher-shutdown
Sep 15, 2026
Merged

code-yeongyu merged 3 commits into
mainfrom
fix/rpc-close-ordering-and-watcher-shutdown

Conversation

@code-yeongyu

@code-yeongyu code-yeongyu commented Sep 14, 2026

Copy link
Copy Markdown
Owner

What

RPC session close and config-watcher shutdown now observe ownership barriers on every path, including the interleavings that the previous patch-shaped port missed.

  • close_session acknowledgements and session_closed events are published only after the session registry has removed the entry. Worker-failure terminals use the same barrier, so an immediate list_sessions never returns the closed session.
  • Watch-worker registration checks a shared cancellation flag before and after fs.watch. A shutdown that wins the post-load/pre-registration gap closes the native handle instead of retaining it.
  • ConfigReloadWatchEngine.close() cancels synchronously and joins returned disposers; repeated close shares that join.
  • Reentrant RPC shutdown() joins in-flight disposal and keeps a failure exit code (serializer-error overlapping stdin EOF).
  • Nonpersistent RPC probes do not start OS watchers.

Why

An immediate list_sessions after close must not observe the closed handle, including when the worker fails instead of a clean close. Fire-and-forget watcher unsubscribe during process exit left native streams running into teardown. Snapshot-only RPC probes never needed live watches.

Tests

Seam-driven regressions cover successful close vs grace deadline, worker error/failure frames, queued vs admitted watcher cancellation, reentrant shutdown join, and persistent vs nonpersistent RPC probe watching. Related watch-message assertions now allow the cancellation token field.

Coordination

Does not edit host-lifecycle.ts or host-ensure.ts. Open PR #1662 also edits CHANGELOG.md and packages/coding-agent/src/modes/rpc/changes.md; those changelog hunks may need a combine on merge.

Refs #1656

Plan: .omo/plans/omo-dependency-diet.md


Summary by cubic

Fixes RPC session close ordering and watcher shutdown so an immediate list_sessions after close never returns the closed session and native watchers do not outlive teardown.

  • close_session acknowledgements and session_closed events now wait for the session registry to remove the entry, including worker-failure terminals; closeMarked still returns at the grace deadline so a stuck worker cannot hang cancel/close.
  • Watcher registration checks a shared cancellation flag before and after fs.watch; close() cancels synchronously and joins all disposers, and repeated close shares that join.
  • Reentrant RPC shutdown() joins in-flight disposal and preserves a non-zero exit code.
  • Nonpersistent RPC probes (no session file) no longer start OS watches.
  • Regression tests isolate post-watch cancellation from a later unwatch delivery.
  • Changelog files have additions that may conflict with open PR fix(rpc): record connection edges before Windows named-pipe idle exit #1662; combine on merge.

Refs #1656

Written for commit dcc0dd2. Summary will update on new commits.

Review in cubic

Close acknowledgements and session_closed, including worker-failure
terminals, wait for the session registry to drop the handle. closeMarked
still returns at the close-grace deadline so a worker stuck in a syscall
cannot wedge cancel. Watcher registration checks cancellation before and
after fs.watch; close() joins disposers; reentrant RPC shutdown shares
that join and keeps a failure exit code; nonpersistent RPC probes start
no watchers.

Plan: .omo/plans/omo-dependency-diet.md
@code-yeongyu
code-yeongyu force-pushed the fix/rpc-close-ordering-and-watcher-shutdown branch from 7993fca to 08bffe7 Compare September 15, 2026 09:10
The admitted interleaving posts unwatch during fs.watch. Delivering that
unwatch in the same IPC drain hid a missing post-watch close. Snapshot
the queued commands so only the watch message runs.

Plan: .omo/plans/omo-dependency-diet.md
finalizeClose waits on registry.peek().closeCompletion. The joined-close
fakes omitted peek, so close_session threw TypeError before publishing.

Plan: .omo/plans/omo-dependency-diet.md
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.

1 participant