Skip to content

(5/7) feat(session): process-lifecycle layer — supervisor spawns N session workers + router#1565

Open
guapisolo wants to merge 3 commits into
mainfrom
refactor/session-mp-lifecycle
Open

(5/7) feat(session): process-lifecycle layer — supervisor spawns N session workers + router#1565
guapisolo wants to merge 3 commits into
mainfrom
refactor/session-mp-lifecycle

Conversation

@guapisolo

@guapisolo guapisolo commented Jul 3, 2026

Copy link
Copy Markdown
Collaborator

Summary

The process-lifecycle layer of the multi-process session server, split out of #1519 for reviewability: SessionServerSupervisor spawns ("spawn" context) N session workers + 1 thin router over socketpairs, gates readiness on the router's /health reporting every worker healthy, fail-fasts on any child death, and tears the whole group down with no orphans. Nothing calls the supervisor yet — launch wiring and the removal of the single-process chassis land in the follow-up PRs.

Stacked on #1569#1510#1563#1518. Base = refactor/session-mp-dataplane. Review/merge after #1518; merge order within the split: this → test-harness PR → #1519.

What's here

  • supervisor.py — spawn-context children (a forked child would inherit this Ray actor's threads/finalizers, e.g. wandb's service thread, and deadlock); the parent closes every socket end it holds so a child death is observable as EOF; readiness raises early if a child dies while loading its tokenizer; a monitor thread records the first death and tears the group down (SIGTERM → grace → SIGKILL, atexit-registered); check() re-raises the recorded failure for the rollout path.
  • router.run_router — the router process entry point; imports nothing from core/worker, so the router process never loads the tokenizer/transformers stack.
  • ipc.set_pdeathsig — the PR_SET_PDEATHSIG helper moves here (stdlib-only) so the router can use it too; the worker's private copy is replaced by the shared helper.
  • tests/fast/router/test_session_supervisor.py — spawns real worker+router processes, drives create/chat/get end-to-end over IPC, then kills a worker and asserts check() raises and no child is orphaned.

Testing

  • pytest tests/fast/router96 passed at this commit (the in-process chassis is untouched here; the suite is green on this PR standing alone).

🤖 Generated with Claude Code

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a multi-process session server supervisor (SessionServerSupervisor) that manages the lifecycle of N session workers and 1 router process, ensuring fail-fast behavior on child process deaths. It also consolidates parent-death signaling (set_pdeathsig) and adds end-to-end tests. The review feedback highlights several critical robustness improvements for the supervisor, including: preventing process leaks during startup failures by tracking processes immediately, resolving a race condition in the monitor loop during shutdown, serializing concurrent shutdown calls with a lock, supporting IPv6 addresses in health checks, and avoiding memory leaks by unregistering the atexit handler upon shutdown.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread miles/rollout/session/supervisor.py
Comment thread miles/rollout/session/supervisor.py
Comment thread miles/rollout/session/supervisor.py
Comment thread miles/rollout/session/supervisor.py
Comment thread miles/rollout/session/supervisor.py Outdated
@guapisolo guapisolo force-pushed the refactor/session-mp-lifecycle branch from 996fd19 to c2af32a Compare July 3, 2026 03:29
@guapisolo guapisolo force-pushed the refactor/session-mp-dataplane branch from 3421e64 to 801c443 Compare July 3, 2026 03:29
@guapisolo guapisolo changed the title feat(session): process-lifecycle layer — supervisor spawns N session workers + router (5/7) feat(session): process-lifecycle layer — supervisor spawns N session workers + router Jul 3, 2026
@guapisolo guapisolo force-pushed the refactor/session-mp-dataplane branch from 801c443 to d964716 Compare July 6, 2026 04:59
@guapisolo guapisolo requested a review from Shi-Dong as a code owner July 6, 2026 04:59
@guapisolo guapisolo force-pushed the refactor/session-mp-lifecycle branch from c2af32a to 0fd7c91 Compare July 6, 2026 05:14
Base automatically changed from refactor/session-mp-dataplane to main July 6, 2026 05:36
…workers + router

SessionServerSupervisor runs in the rollout process and owns the child
processes of the multi-process session server: start() spawns ("spawn"
context — a forked child would inherit this Ray actor's threads and
finalizers, e.g. wandb's service thread, and deadlock) N workers plus one
thin router over socketpairs, closes the parent's socket ends so a child
death is observable as EOF, and gates readiness on the router reporting
every worker healthy. A monitor thread records the first child death and
tears the whole group down (SIGTERM, grace, SIGKILL — no orphans);
check() re-raises that failure so the rollout path can fail loudly
instead of hanging on a dead hash shard.

run_router is the router process entry point; it imports nothing from
core/worker, so the router process never loads the
tokenizer/transformers stack. set_pdeathsig moves to ipc
(stdlib-only) for the same reason, and the worker's private copy becomes
the shared helper.

test_session_supervisor spawns real worker+router processes, drives
create/chat/get end-to-end over IPC, then kills a worker and asserts
check() raises and no child is orphaned.

Nothing calls the supervisor yet; launch wiring lands separately.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@guapisolo guapisolo force-pushed the refactor/session-mp-lifecycle branch from 0fd7c91 to d7d0a7d Compare July 6, 2026 05:57
guapisolo and others added 2 commits July 6, 2026 08:40
…hutdown races

- start(): register each child in _procs immediately after start() and widen the
  teardown try to the whole spawn phase, so a mid-spawn failure reaps every
  already-started child instead of orphaning them
- _monitor_loop(): re-check _shutdown_done after observing a dead child; since
  shutdown() flips the flag before terminate(), a death seen with the flag still
  False is provably a real failure, never a false positive from normal teardown
- shutdown(): serialize under a lock so a concurrent caller blocks until the
  group is fully reaped instead of returning while termination is in flight

Addresses Gemini review comments 1-3 on #1565.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sweep the RST-style ``double backticks`` out of the session-server
docstrings and comments — the repo convention is markdown-style
single backticks, and the doubled form reads as a typo in review.
Comment-only change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@guapisolo guapisolo requested a review from Zhichenzzz as a code owner July 6, 2026 10:05

@Shi-Dong Shi-Dong left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems that the session supervisor only catches the case where a child process dies. If it hangs, nothing is triggered.

Not sure whether this is a lethal issue, though. LGTM now to deblock.

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.

2 participants