Skip to content

[Bugfix][MoRIIO] Keep discovery heartbeats running while workers hold the GIL - #59441

Merged
tjtanaa merged 6 commits into
vllm-project:mainfrom
whx-sjtu:whx/moriio-discovery-heartbeat
Oct 3, 2026
Merged

tjtanaa merged 6 commits into
vllm-project:mainfrom
whx-sjtu:whx/moriio-discovery-heartbeat

Conversation

@whx-sjtu

@whx-sjtu whx-sjtu commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Overview

Keep MoRIIO discovery registration alive during worker GIL holds and temporary
router outages. Report unexpected heartbeat subprocess exit through worker
completion polling. This independent fix was extracted from #58968, which no
longer contains the implementation; it has no dependency on the K3 data path.

Claims

rank-0 worker -> heartbeat subprocess -> unchanged MessagePack registration
  temporary send timeout -> retry until the worker exits
  unexpected child exit -> worker get_finished() raises with its exit code
  worker shutdown / parent pipe EOF -> stop and reap the child

Validation

  • Before: main's actual threaded sender fails the 300 ms GIL-hold test.
    At pre-review HEAD 512a877511, the new router-outage test fails to resume
    registration; killing the child or ending its input pipe leaves worker
    completion polling silent (3 failed).
  • After: 46 passed, 0 skipped across the existing proxy-routing and
    MoRIIO TP-ACK suites. Tests use real subprocesses and loopback ZeroMQ for
    GIL independence, initial registration, router disappearance until the send
    queue times out, registration after the router returns, parent death,
    repeated shutdown, and propagation of both signal and zero-code child exits.
  • Applicable pre-commit hooks, including mypy 3.10, and manual mypy 3.12 passed.
VLLM_TARGET_DEVICE=cpu PYTHONPATH="$PWD" .venv/bin/python -m pytest -q \
  tests/v1/kv_connector/unit/test_moriio_proxy_routing.py \
  tests/v1/kv_connector/unit/test_moriio_tp_ack.py

.venv/bin/pre-commit run --files \
  vllm/distributed/kv_transfer/kv_connector/v1/moriio/moriio_heartbeat.py \
  vllm/distributed/kv_transfer/kv_connector/v1/moriio/moriio_connector.py \
  tests/v1/kv_connector/unit/test_moriio_proxy_routing.py \
  tests/v1/kv_connector/unit/test_moriio_tp_ack.py

.venv/bin/pre-commit run mypy-3.12 --hook-stage manual --files \
  vllm/distributed/kv_transfer/kv_connector/v1/moriio/moriio_heartbeat.py \
  vllm/distributed/kv_transfer/kv_connector/v1/moriio/moriio_connector.py \
  tests/v1/kv_connector/unit/test_moriio_proxy_routing.py \
  tests/v1/kv_connector/unit/test_moriio_tp_ack.py

Validation covers process and worker lifecycle on CPU. No model-output,
accuracy, throughput, or end-to-end model-serving result is claimed for this
isolated control-plane change.

Details

The finite retry limit previously treated ZeroMQ send timeouts during temporary
disconnection as terminal. Those timeouts now retry for the worker lifetime;
other repeated ZMQ errors still terminate the child. The parent previously
never inspected child status. It now checks on each worker completion poll,
including unexpected exit code zero. An idle worker observes a fatal child
exit when it next polls; this does not introduce a background restart manager.

Door: Two-way. Reverting restores the threaded sender without changing the
discovery wire format. Blast radius: MoRIIO workers with a discovery proxy.

AI assistance was used for implementation, tests, extraction and PR preparation.


Pull Request Checklist
  • I used vLLM's /pr-checklist skill.
  • AI assistance was used during the creation of this PR.
  • Design Fit: Reuses worker completion polling and the existing heartbeat owner.
  • Testing and Validation: Real process/ZMQ regressions and worker propagation tests; model-serving scope is stated above.
  • Code Quality and Style: Scoped changes; pre-commit and mypy passed.
  • Pull Request Contents: Includes cause, before/after evidence, reproduction commands and limitations.

@mergify mergify Bot added bug Something isn't working kv-connector labels Sep 30, 2026
@whx-sjtu
whx-sjtu marked this pull request as ready for review September 30, 2026 14:33

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

Extract the process-based discovery sender from vllm-project#58968 onto main. Preserve the discovery payload and rank-zero startup guard, stop the helper on explicit shutdown or parent pipe EOF, and retain the GIL-starvation and parent-exit lifecycle regressions.

Co-authored-by: Codex <noreply@openai.com>
Signed-off-by: whx-sjtu <xiaowang990929@gmail.com>
@whx-sjtu
whx-sjtu force-pushed the whx/moriio-discovery-heartbeat branch from 944b575 to 512a877 Compare October 1, 2026 03:44
failures = 0
with zmq.Context() as context, context.socket(zmq.DEALER) as sock:
sock.setsockopt(zmq.LINGER, 0)
sock.setsockopt(zmq.SNDTIMEO, 1000)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Could we preserve recovery after a temporary discovery/router outage here?

This adds SNDTIMEO=1000, and lines 75–79 terminate the helper after max_retries consecutive ZMQErrors. The parent never monitors or restarts _process, so once the helper exits this worker permanently stops refreshing its discovery registration even if the router/network later recovers.

This is slightly different from the current _ping path on main: the socket uses ZeroMQ's default infinite send timeout, so once its outbound queue is full the sender blocks and can resume when connectivity comes back rather than terminating the heartbeat owner.

Could we either:

  1. keep retrying recoverable send errors for the lifetime of the worker, or
  2. have the parent detect/restart a failed heartbeat subprocess?

It would also be useful to add a regression test that makes discovery unavailable and then restores it, verifying that the same live worker resumes registration without requiring a vLLM restart.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agreed. Working on it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

Retry temporary ZMQ send timeouts for the worker lifetime. Surface unexpected heartbeat child termination, including exit code zero, from worker completion polling. Cover real router outage recovery and child exits.

Co-authored-by: Codex <noreply@openai.com>
Signed-off-by: whx-sjtu <xiaowang990929@gmail.com>

@tjtanaa tjtanaa left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

@tjtanaa tjtanaa added rocm Related to AMD ROCm ready ONLY add when PR is ready to merge/full CI is needed labels Oct 1, 2026
@tjtanaa
tjtanaa requested a review from orozery as a code owner October 1, 2026 13:46
@github-actions

github-actions Bot commented Oct 1, 2026

Copy link
Copy Markdown

✅ @whx-sjtu, CI is now available for this PR.

  • /ci run starts upstream CI; /amd-ci run starts AMD CI only.
  • Your branch must contain every commit currently on its upstream target branch. Merge or rebase onto the latest target branch, then rerun the command. Append --allow-stale to a run command to test an outdated branch at your own risk.
  • /ci retry retries failed jobs in the CI build for the current PR head. If the current head has no CI build, it starts a new CI build for the current head containing only jobs that failed in the latest earlier CI build for this PR.
  • /amd-ci retry retries failed jobs in AMD CI for the current PR head. Use /amd-ci run when the current head has no AMD CI build.
  • /ci cancel cancels scheduled or running CI builds for this PR branch; /amd-ci cancel does the same for AMD CI only.

@tjtanaa
tjtanaa enabled auto-merge (squash) October 1, 2026 13:47
@whx-sjtu

whx-sjtu commented Oct 2, 2026

Copy link
Copy Markdown
Contributor Author

/amd-ci run

@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown

✅ Triggered Buildkite AMD CI #14007 for commit 1bd19cd9f3dc.

@tjtanaa

tjtanaa commented Oct 2, 2026

Copy link
Copy Markdown
Member

/ci run

@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown

❌ This PR is 9 commits behind upstream main. Your branch must contain every commit currently on upstream main. No new CI build was started. Merge or rebase onto the latest main, then rerun /ci run. To test this branch at your own risk, use /ci run --allow-stale.

@whx-sjtu

whx-sjtu commented Oct 2, 2026

Copy link
Copy Markdown
Contributor Author

/ci run

@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown

✅ Triggered Buildkite CI #92574 for commit a7910aee1e88.

@whx-sjtu

whx-sjtu commented Oct 3, 2026

Copy link
Copy Markdown
Contributor Author

/ci run

@github-actions

github-actions Bot commented Oct 3, 2026

Copy link
Copy Markdown

✅ Triggered Buildkite CI #92760 for commit ee489b05538b.

@vllm-agent

Copy link
Copy Markdown
Contributor

CI selector (shadow): 2 test steps (5 jobs) instead of 8 (13 jobs)

Shadow mode: this changes nothing about what CI runs. It shows what the evidence-based selector would pick for this PR, next to today's rules. How it works.

Feedback welcome: reply here if it would skip a step this change needs, or runs something unrelated.

steps (jobs) Today's rules Selector Would skip Would add
NVIDIA, CPU and others 8 (13) 2 (5) 6 (8) 0 (0)
AMD mirrors 17 (20) 1 (4) 16 (16) 0 (0)
Selector would run (2)
  • v1-kv-connectors ×4
  • v1-others-cpu
Would skip (today's rules run them) (6)
  • ascend-npu-test
  • cpu-language-generation-and-pooling-model-tests ×3
  • v1-core
  • v1-executor-worker
  • v1-kv-offload
  • v1-metrics-lmeval
Would add (today's rules do not run them) (0)

none

AMD mirrors: would skip (16)
  • extract-hidden-states-integration-2-gpus
  • fault-tolerance-e2e-2xh100
  • fusion-and-compile-unit-tests-2xb200
  • fusion-e2e-tp2-ar-rms-config-sweep-h100
  • fusion-e2e-tp2-asynctp-config-sweep-h100
  • fusion-e2e-tp2-b200
  • fusion-e2e-tp2-quick-h100
  • gemm-rs-ar-2xb200
  • kernels-fusedmoe-layer-test-2-b200s
  • kernels-fusedmoe-layer-test-2-h100s
  • kernels-minimax-reduce-rms-test-2-gpus
  • platform-tests
  • v1-core
  • v1-executor-worker
  • v1-kv-offload
  • v1-metrics-lmeval
AMD mirrors: would add (0)

none

4 changed files · base e319f86f15 · head ee489b0553 · Python record: build 92706 at 6e517b15c1 · kernel record: table 6e517b1 (build 92706), map 6e517b1 · not counted: 10 build steps, 5 A100 steps the generator no longer emits, 7 optional steps the selector would also run

@tjtanaa
tjtanaa merged commit f03026a into vllm-project:main Oct 3, 2026
50 of 51 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working kv-connector ready ONLY add when PR is ready to merge/full CI is needed rocm Related to AMD ROCm

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants