Skip to content

feat(RL): add worker discovery endpoint - #9681

Merged
biswapanda merged 7 commits into
mainfrom
bis/rl-workers-discovery
Jun 9, 2026
Merged

feat(RL): add worker discovery endpoint#9681
biswapanda merged 7 commits into
mainfrom
bis/rl-workers-discovery

Conversation

@biswapanda

@biswapanda biswapanda commented May 18, 2026

Copy link
Copy Markdown
Contributor

Overview

Adds the frontend worker discovery surface for RL frameworks. This is stacked on the worker-side RL admin routes PR and exposes only GET /v1/rl/workers; admin execution remains direct-to-worker through workers[*].system_url and /engine/<route>.

Changes

  • Add the dynamo-rl crate with read-only GET /v1/rl/workers.
  • Discover live dyn://<namespace>.<component>.rl instances and query them with {"method":"routes"}.
  • Wire the frontend dedicated RL discovery listener through DYN_ENABLE_RL=true and DYN_RL_PORT defaulting to 8001.
  • Add focused vLLM E2E pytest coverage for discovery plus direct worker /engine/* admin calls.

Validation

  • cargo check -p dynamo-rl
  • cargo check -p dynamo-llm
  • .venv/bin/python -m pytest tests/rl/test_worker_discovery.py::test_rl_worker_discovery_and_engine_admin_routes -q
  • Prime-rl full-weight filesystem E2E passed in /home/biswaranjanp/dev/rl/work/bis-dev/may-18/fullweight-fs-e2e-simple

Notes

supersedes #9382

Summary by CodeRabbit

Release Notes

  • New Features

    • Added RL worker discovery API enabling discovery of live worker instances via /v1/rl/workers endpoint
    • HTTP service now supports configurable RL discovery listener on a separate port
    • Worker metadata includes routes, component information, and optional model names
  • Tests

    • Added end-to-end tests for RL worker discovery and engine admin routes

@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 frontend `python -m dynamo.frontend` and `dynamo-run in=http|text|grpc` labels 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-discovery branch from df75f6b to 0d67a1b Compare May 18, 2026 16:49
@biswapanda
biswapanda force-pushed the bis/rl-workers-admin-routes branch from d4a15b6 to 4d18d72 Compare May 18, 2026 16:51
@biswapanda
biswapanda force-pushed the bis/rl-workers-discovery branch from 0d67a1b to f28a1c2 Compare May 18, 2026 16:51
@biswapanda
biswapanda force-pushed the bis/rl-workers-discovery branch from f28a1c2 to ecae356 Compare May 18, 2026 16:56
@biswapanda biswapanda changed the title feat(rl): add worker discovery endpoint feat(RL): add worker discovery endpoint May 28, 2026
@biswapanda
biswapanda force-pushed the bis/rl-workers-admin-routes branch 2 times, most recently from 31f9cbc to 9d1d61c Compare June 6, 2026 21:01
@biswapanda
biswapanda force-pushed the bis/rl-workers-discovery branch from ecae356 to 8f0be53 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
@biswapanda
biswapanda force-pushed the bis/rl-workers-discovery branch from 8f0be53 to bbe4095 Compare June 6, 2026 21:19
@biswapanda
biswapanda force-pushed the bis/rl-workers-admin-routes branch from 3ca7ddd to 489c4a0 Compare June 7, 2026 07:28
@biswapanda
biswapanda force-pushed the bis/rl-workers-discovery branch from bbe4095 to 57ff99b Compare June 7, 2026 07:28
@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

This PR introduces a new dynamo-rl crate providing HTTP-based discovery of live RL worker instances, integrates it into the existing HTTP service with a separate listener port, and includes comprehensive end-to-end tests validating worker discovery and engine admin route access.

Changes

RL Worker Discovery Feature

Layer / File(s) Summary
Workspace and crate integration
Cargo.toml, lib/llm/Cargo.toml, lib/rl/Cargo.toml
Workspace adds lib/rl member and dynamo-rl dependency; lib/llm depends on dynamo-rl; manifest defines RL crate with workspace-managed dependencies.
RL worker discovery core implementation
lib/rl/src/lib.rs
Public endpoint GET /v1/rl/workers discovers workers by querying Dynamo endpoint/model instances, filtering by configured RL endpoint and component allowlist, querying each worker's routes via request-plane direct calls, and returning sorted/deduplicated worker metadata with routes, optional system URL, and model association.
HTTP service RL configuration and struct updates
lib/llm/src/http/service/service_v2.rs
HttpService struct adds rl_router and rl_port fields; HttpServiceConfig builder adds enable_rl, rl_port, and optional runtime; router building conditionally creates RL router when enabled; startup spawns separate listener for RL discovery on configured port.
Service entry point and runtime wiring
lib/llm/src/http/service/openai.rs, lib/llm/src/entrypoint/input/http.rs
openai.rs adds rl_router constructor building RL state from environment; http.rs wires distributed runtime to service builder.
End-to-end integration tests
tests/rl/test_worker_discovery.py, tests/rl/weight_update_worker.py, tests/rl/__init__.py
Test module spins up frontend and vLLM worker with RL enabled, polls discovery endpoint until worker appears, validates worker metadata and route exposure, exercises admin endpoints via discovered admin_url, and confirms inference works; includes test worker extension stubs and fixture/helper infrastructure.

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding a worker discovery endpoint for the RL framework, which is the central focus of this PR.
Description check ✅ Passed The description includes Overview, Details (Changes section), and explicit Related Issues statement. All required template sections are present and filled with substantive information about the PR's scope and validation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@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: 6

🤖 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 `@lib/llm/src/http/service/service_v2.rs`:
- Around line 477-508: The RL discovery listener currently only logs bind
failures in spawn_rl_listener_if_configured, leaving the main HTTP service
running; change the Err(e) branch so the process fails fast: after logging the
error (address = %rl_addr, error = %e) call std::process::exit(1) (or otherwise
trigger global shutdown) so the service does not start silently without RL
discovery; update the Err branch inside spawn_rl_listener_if_configured (the
match on tokio::net::TcpListener::bind) to perform the exit/shutdown
immediately.

In `@lib/rl/src/lib.rs`:
- Around line 242-243: The call to wait_for_client_targets currently hardcodes
Duration::from_secs(5) and ignores its result, so the configured request_timeout
isn't respected and timeouts are swallowed; update the calls (the one at
wait_for_client_targets(&client, &[target.instance_id],
Duration::from_secs(5)).await and the similar block at lines ~276-287) to use
the configured request_timeout Duration (e.g., request_timeout variable or
client.request_timeout) instead of 5s, await the Result and propagate or return
an Err on timeout rather than discarding it, and adjust call sites/signatures if
needed so wait_for_client_targets returns a Result that callers check and handle
consistently.

In `@tests/rl/test_worker_discovery.py`:
- Around line 25-26: The test is currently marked as pre_merge
(pytest.mark.pre_merge) but is an expensive e2e with `@pytest.mark.timeout`(900);
change the marker to pytest.mark.post_merge on the test decorator(s) (replace
pytest.mark.pre_merge with pytest.mark.post_merge) or, if it truly must remain
pre_merge, add an explicit justification comment above the decorator(s)
explaining why this long-running test is critical for pre-merge gating; apply
the same change or justification to the other occurrences around the block
referenced (the markers at the later lines 210-213).
- Around line 90-93: _prepare_log_dir currently creates/deletes a relative
directory under the repo (f"{request.node.name}_{suffix}") which can collide and
writes into the tree; replace that with pytest's temporary directory by
obtaining the tmp_path fixture (use request.getfixturevalue("tmp_path") if you
don't want to change the call signature) and create/return a subdirectory under
it (e.g., tmp_path / f"{request.node.name}_{suffix}"), removing the manual
rmtree and returning the absolute path string so logs are written to
pytest-managed temp locations instead of the repository.
- Around line 24-31: The pytest markers on the pytestmark list are missing the
required VRAM and vLLM KV sizing markers; update the pytestmark list (the
variable pytestmark that decorates this test and references TEST_MODEL) to
include pytest.mark.profiled_vram_gib(N) with the correct GiB value for
TEST_MODEL and the vLLM KV sizing marker pytest.mark.vllm_kv_sizing(...) (or the
project’s canonical vLLM KV marker) so CI schedulers can place it safely.

In `@tests/rl/weight_update_worker.py`:
- Around line 33-35: Replace the runtime assert in update_weights_from_path with
explicit validation: in the update_weights_from_path(self, weight_path: str)
method check if not weight_path (and optionally if not isinstance(weight_path,
str)) and raise a clear exception (e.g., raise ValueError("weight_path must be a
non-empty string")) instead of using assert, then proceed with the existing
logic and return None as before.
🪄 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: 50522a81-a15a-43e2-8ef9-051af1b95cd9

📥 Commits

Reviewing files that changed from the base of the PR and between 7ec3512 and e487c9e.

⛔ Files ignored due to path filters (3)
  • Cargo.lock is excluded by !**/*.lock
  • lib/bindings/kvbm/Cargo.lock is excluded by !**/*.lock
  • lib/bindings/python/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (10)
  • Cargo.toml
  • lib/llm/Cargo.toml
  • lib/llm/src/entrypoint/input/http.rs
  • lib/llm/src/http/service/openai.rs
  • lib/llm/src/http/service/service_v2.rs
  • lib/rl/Cargo.toml
  • lib/rl/src/lib.rs
  • tests/rl/__init__.py
  • tests/rl/test_worker_discovery.py
  • tests/rl/weight_update_worker.py

Comment thread lib/llm/src/http/service/service_v2.rs Outdated
Comment thread lib/rl/src/lib.rs Outdated
Comment thread tests/rl/test_worker_discovery.py
Comment thread tests/rl/test_worker_discovery.py Outdated
Comment thread tests/rl/test_worker_discovery.py Outdated
Comment thread tests/rl/weight_update_worker.py
@biswapanda
biswapanda enabled auto-merge (squash) June 9, 2026 20:08
@biswapanda
biswapanda merged commit 6101ffc into main Jun 9, 2026
93 checks passed
@biswapanda
biswapanda deleted the bis/rl-workers-discovery branch June 9, 2026 21:06
yao531441 pushed a commit to yao531441/dynamo that referenced this pull request Jun 10, 2026
Signed-off-by: Yao, Qing <qing.yao@intel.com>
nv-tusharma added a commit that referenced this pull request Jun 11, 2026
test_rl_worker_discovery_and_engine_admin_routes launches its vLLM worker via a
hardcoded command that omitted the GPU-memory budget every other vLLM e2e test
injects. Under the parallel GPU scheduler the worker is bin-packed onto a shared
GPU but ignored its _PROFILE_OVERRIDE_VLLM_KV_CACHE_BYTES budget, so vLLM fell
back to gpu_memory_utilization=0.9, demanded ~90% of the whole card, and crashed
during engine init ("Free memory ... less than desired GPU memory utilization")
with exit code 1 — surfacing as "Main server process exited with code 1 while
waiting for health check". 77.9% failure rate on main since #9681.

Route the worker command through build_gpu_mem_args("build_vllm_gpu_mem_args")
like the standard vLLM workers, so it honors the scheduler's
--kv-cache-memory-bytes budget under parallel runs and uses a conservative
--gpu-memory-utilization 0.4 fallback when run serially. The test already
declares requested_vllm_kv_cache_bytes(331_801_000); this makes the worker
actually respect it (tests/README.md documents this as a hard requirement).

Reproduced locally under simulated bin-packing (43 GiB held, ~3.5 GiB free):
the unfixed worker dies at the vLLM free-memory check (exit 1); with the fix the
engine initializes within its 0.31 GiB KV budget and proceeds past the memory gate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.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

feat frontend `python -m dynamo.frontend` and `dynamo-run in=http|text|grpc` size/XXL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants