Skip to content

pd: producer failure handling, readiness gate and stage metrics (#238, #246, #249) - #282

Merged
gspark-etri merged 1 commit into
optimus-rmfrom
fix/238-pd-producer-lifecycle
Oct 30, 2026
Merged

gspark-etri merged 1 commit into
optimus-rmfrom
fix/238-pd-producer-lifecycle

Conversation

@gspark-etri

Copy link
Copy Markdown
Collaborator

Background

A failed PD prefill producer could leave requests pending, keep /ready green and get the batcher quarantined on the next admission; producer stage durations were not exported. This lands that work from a draft stack, with two fixes found in review.

Changes

From feat/249-pd-stage-metrics (#239, #247, #250):

  • opt_prime/opt_prime/accel/pd/pd_batching.py: SubprocessPrefillWorker settles every pending future on child exit or a malformed reply, rejects new work after a terminal failure, cleans up the child and shared memory on failed startup, exposes ready; PrefillWorkerPool.ready.
  • opt_prime/opt_prime/accel/serve/batched.py: BatchedService.ready, admission returns 503 retryable while the producer is unready, airm_pd_producer_seconds_total{stage=prefill|transfer}.
  • opt_prime/opt_prime/accel/serve/llmd.py: only the /ready hunk (from exp/240-gpu-live-pd...fix/246-pd-producer-readiness); the rest of the file is untouched so the SIGPIPE fix in the serving PR is not reverted.
  • Tests: test_subprocess_prefill_failure.py, test_pd_producer_readiness.py, test_pd_stage_metrics.py (new).

Fixes on top (test first):

  • F1: SubprocessPrefillWorker.close() now closes stdin and waits for the child to exit, then terminate(), then kill(). prefill_server exits its for line in sys.stdin loop on EOF; SIGTERM first skipped the SDK cleanup that releases the RNGD device. Test test_close_lets_child_exit_cleanly_on_stdin_eof. The existing test that a child ignoring SIGTERM is still killed is kept and passes.
  • F2: ProcessPrefillWorker.ready (self._futures is not None and self._proc.is_alive()), so the readiness gate sees a dead child. Test test_dead_process_worker_is_unready_and_rejects_admission: child killed, /ready 503, completion 503 retryable, service not poisoned.

Verification

  • pytest -q tests/test_subprocess_prefill_failure.py tests/test_pd_producer_readiness.py tests/test_pd_stage_metrics.py: 16 passed.
  • Before the fixes: F1 test failed (returncode -15 != 0, no clean-exit marker); F2 test failed (/ready returned 200 after the child was killed).
  • pytest -q tests/test_pd_batching_disagg.py (existing tests of both worker classes): 12 passed.
  • Full suite: CI (cpu-tests).

Compatibility and limits

  • close() can now take up to 2 * timeout (default 5 s each) before SIGKILL for a child that ignores stdin EOF and SIGTERM.
  • A failed producer is not replaced or removed from a pool automatically; replacing it is explicit.
  • The duration metrics are worker-reported seconds for admitted handoffs, not HTTP latency.
  • This PR and the serving PR both edit llmd.py, in separate hunks.

Related Issue

Closes #238
Closes #246
Closes #249

Supersedes #239, #247, #250.

🤖 Generated with Claude Code

…#246, #249)

From feat/249-pd-stage-metrics (#239, #247, #250): SubprocessPrefillWorker
failure settling, producer readiness gating /ready and admission, producer
stage-duration metrics; only the /ready hunk of llmd.py.

Fixes on top:
- SubprocessPrefillWorker.close() closes stdin and waits for a clean exit
  before SIGTERM, then SIGKILL (prefill_server exits on stdin EOF; SIGTERM
  first skipped SDK cleanup that releases the device).
- ProcessPrefillWorker.ready: a dead child now fails readiness and admission
  is rejected with 503 instead of quarantining the batcher.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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