Skip to content

feat(RL): add RL worker admin routes - #9680

Merged
biswapanda merged 14 commits into
mainfrom
bis/rl-workers-admin-routes
Jun 9, 2026
Merged

feat(RL): add RL worker admin routes#9680
biswapanda merged 14 commits into
mainfrom
bis/rl-workers-admin-routes

Conversation

@biswapanda

@biswapanda biswapanda commented May 18, 2026

Copy link
Copy Markdown
Contributor

Overview

Adds the worker-side RL admin surface needed by prime-rl on top of bis/nvext-tito-vllm. This PR keeps the frontend out of admin execution and prepares workers to advertise route metadata over the request plane.

Changes

  • Add dynamo.common.rl helpers for RL route descriptors and LoRA request validation.
  • Register vLLM RL admin routes on the worker system server under /engine/<route>.
  • Register dyn://<namespace>.<component>.rl only as a route-descriptor request-plane endpoint.
  • Advertise worker system_url through the Python runtime binding.
  • Reuse existing vLLM load_lora / unload_lora handlers when LoRA is enabled.

Validation

  • .venv/bin/python -m pytest components/src/dynamo/common/tests/test_rl_admin.py -q
  • .venv/bin/python -m py_compile components/src/dynamo/common/rl/admin.py components/src/dynamo/vllm/handlers.py components/src/dynamo/vllm/worker_factory.py

Notes

supersedes #9382


Open in Devin Review

Summary by CodeRabbit

  • New Features

    • Added RL admin request-plane endpoints: health, pause/resume generation, flush cache, abort request, route dispatch, and weight-update lifecycle
    • Weight management: updates from disk/distributed/tensor and coordinated update groups
    • LoRA hot-swap with explicit hot_swap reporting and stricter request validation
    • More robust abort handling during generation to avoid cancellation side effects
  • Tests

    • New unit tests covering RL admin routing, validation, endpoints, and deferred-abort behavior

@biswapanda
biswapanda requested review from a team as code owners May 18, 2026 15:46
@biswapanda
biswapanda requested a review from a team May 18, 2026 15:46
@github-actions github-actions Bot added feat backend::vllm Relates to the vllm backend labels May 18, 2026
@biswapanda biswapanda self-assigned this May 18, 2026
@biswapanda biswapanda changed the title feat(vllm): add RL worker admin routes feat(RL): add RL worker admin routes May 18, 2026
@biswapanda
biswapanda force-pushed the bis/rl-workers-admin-routes branch from 84f0357 to d4a15b6 Compare May 18, 2026 16:07
@biswapanda
biswapanda force-pushed the bis/rl-workers-admin-routes branch from d4a15b6 to 4d18d72 Compare May 18, 2026 16:51
Comment thread components/src/dynamo/common/rl/admin.py Outdated
Comment thread components/src/dynamo/vllm/handlers.py Outdated
Comment thread components/src/dynamo/vllm/handlers.py Outdated
@biswapanda
biswapanda force-pushed the bis/nvext-tito-vllm branch 3 times, most recently from 81a65d6 to 15cf6d5 Compare May 26, 2026 09:03
@biswapanda
biswapanda force-pushed the bis/nvext-tito-vllm branch 2 times, most recently from 7a2a3cd to 68f5c1c Compare June 6, 2026 07:37
@biswapanda
biswapanda force-pushed the bis/rl-workers-admin-routes branch from 4d18d72 to 31f9cbc Compare June 6, 2026 08:41
@biswapanda
biswapanda force-pushed the bis/rl-workers-admin-routes branch from 31f9cbc to 9d1d61c Compare June 6, 2026 21:01
@biswapanda
biswapanda force-pushed the bis/rl-workers-admin-routes branch from 9d1d61c to 3ca7ddd Compare June 6, 2026 21:19
Base automatically changed from bis/nvext-tito-vllm to main June 6, 2026 23:32
- shield the deferred-abort await so a cancelled admin route / disconnected
  client cannot cancel the in-flight engine abort
- wire the deferred-abort guard into _generate_text_mode (disagg decode text
  mode) so admin abort_request also defers there and pre-first-token aborts are
  safe
- run flush_cache under _pause_lock so it cannot race a locked weight update
- invalidate prefix/KV cache after weight updates (disk + distributed) before
  resume so stale cache is not reused under new weights
- roll back the engine adapter (remove new, re-add old), not just metadata,
  when a LoRA hot-swap's prefix-cache reset fails
- coerce non-dict admin request bodies to {} so malformed JSON returns a typed
  error dict instead of a 500
…ilures

- admin routes now reject non-object JSON bodies with a typed error instead of
  normalizing them into a default action (None still treated as empty {})
- _DeferredAbort records the engine-abort exception; abort_request reports it
  (and escalates EngineDeadError) instead of a false 'ok'
- shield the abort task in _DeferredAbort.close() too
- regression tests for body rejection and deferred-abort failure surfacing
…ngine death

- _DeferredAbort.abort() returns immediately for a pre-first-token deferred
  abort (the real abort fires in the background on first token) so the admin
  abort_request route and disconnect monitor never hang waiting for a token
- thread an on_engine_dead hook so a deferred/background abort that hits
  EngineDeadError shuts the runtime down on any path (admin, monitor, deferred),
  not just the synchronous admin route
- regressions for no-block-before-first-token and engine-dead escalation
abort() no longer blocks pre-first-token (the real abort is deferred to a
background task), so the tests now await guard.abort() directly and observe the
parked _abort_task / drive it via signal_first_token, and the _capture mock
accepts the new on_engine_dead arg.
@biswapanda
biswapanda removed the request for review from a team June 8, 2026 23:04
@biswapanda
biswapanda enabled auto-merge (squash) June 8, 2026 23:04
@biswapanda

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
components/src/dynamo/vllm/handlers.py (1)

3303-3304: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't signal first_token on the synthetic no-output error path.

generate_tokens() emits a synthetic error chunk when res.outputs is empty. This loop calls abort_guard.signal_first_token() for every yielded chunk, so a queued admin/disconnect abort can wake up and execute engine_client.abort() even though no real token was produced yet. That reopens the exact pre-first-token abort window the deferred guard is meant to avoid.

Suggested fix
-                        if abort_guard is not None:
+                        if abort_guard is not None and tok.get("token_ids"):
                             abort_guard.signal_first_token()

If you want to preserve the logic in one place, moving the signal into the normal-output branch inside generate_tokens() is even safer.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/src/dynamo/vllm/handlers.py` around lines 3303 - 3304, The current
loop calls abort_guard.signal_first_token() for every yielded chunk including
the synthetic no-output error from generate_tokens() (when res.outputs is
empty), which reopens the pre-first-token abort window; fix it by only signaling
the abort guard when a real token/output is produced—i.e., guard the call to
abort_guard.signal_first_token() with a check that res.outputs (or the actual
token) is non-empty or move the signal into the normal-output branch inside
generate_tokens() so synthetic error chunks never trigger signal_first_token();
update the code paths that yield chunks to use this check and reference
abort_guard.signal_first_token() and generate_tokens() when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@components/src/dynamo/vllm/handlers.py`:
- Around line 299-301: The defer-abort guard is being removed from registry
before awaiting guard.close(), causing a race where abort_request() can miss the
guard and call engine_client.abort(request_id); change the teardown so the guard
remains registered until close() completes — i.e., await guard.close() while the
registry still maps request_id to the guard, then remove
registry.pop(request_id, None) after the await (or wrap close() in a try/finally
that pops in the finally) so the guard is always discoverable by abort_request()
until close() finishes.

In `@components/src/dynamo/vllm/tests/test_vllm_worker_handler.py`:
- Around line 1310-1388: Add a "unit" test-type marker to these new tests by
applying pytest.mark.unit at module or class scope (e.g., set pytestmark =
[pytest.mark.unit] near the top of the file or add `@pytest.mark.unit` above class
TestRLAdminRouteHardening) so the test suite's marker validation
(tests/report_pytest_markers.py) recognizes the required Test Type category;
keep existing markers intact and ensure the new marker is imported from pytest
if necessary.

---

Outside diff comments:
In `@components/src/dynamo/vllm/handlers.py`:
- Around line 3303-3304: The current loop calls abort_guard.signal_first_token()
for every yielded chunk including the synthetic no-output error from
generate_tokens() (when res.outputs is empty), which reopens the pre-first-token
abort window; fix it by only signaling the abort guard when a real token/output
is produced—i.e., guard the call to abort_guard.signal_first_token() with a
check that res.outputs (or the actual token) is non-empty or move the signal
into the normal-output branch inside generate_tokens() so synthetic error chunks
never trigger signal_first_token(); update the code paths that yield chunks to
use this check and reference abort_guard.signal_first_token() and
generate_tokens() when making the change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: ffe9e48e-91ac-4779-8c97-7be2b14372f2

📥 Commits

Reviewing files that changed from the base of the PR and between 489c4a0 and 319b14e.

📒 Files selected for processing (4)
  • components/src/dynamo/common/rl/admin.py
  • components/src/dynamo/common/tests/test_rl_admin.py
  • components/src/dynamo/vllm/handlers.py
  • components/src/dynamo/vllm/tests/test_vllm_worker_handler.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • components/src/dynamo/common/tests/test_rl_admin.py
  • components/src/dynamo/common/rl/admin.py

Comment thread components/src/dynamo/vllm/handlers.py Outdated
Comment thread components/src/dynamo/vllm/tests/test_vllm_worker_handler.py
Awaiting guard.close() before popping request_id from the registry closed a
teardown race: an out-of-band admin abort_request during close() could miss the
guard and take the unsafe direct engine_client.abort path in the pre-first-token
window (CodeRabbit).
@biswapanda
biswapanda merged commit 81f7f89 into main Jun 9, 2026
92 checks passed
@biswapanda
biswapanda deleted the bis/rl-workers-admin-routes branch June 9, 2026 15:12
yao531441 pushed a commit to yao531441/dynamo that referenced this pull request Jun 10, 2026
Signed-off-by: Yao, Qing <qing.yao@intel.com>
Broduker pushed a commit to Broduker/dynamo that referenced this pull request Jun 12, 2026
Signed-off-by: shenls <shenlinshan@kanzhun.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend::vllm Relates to the vllm backend feat size/XXL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants