Skip to content

fix(vllm): bind discovery topology inside connector templates - #508

Open
YukioZzz wants to merge 1 commit into
NVIDIA:mainfrom
YukioZzz:yichaozhu/discovery-connector-templates
Open

YukioZzz wants to merge 1 commit into
NVIDIA:mainfrom
YukioZzz:yichaozhu/discovery-connector-templates

Conversation

@YukioZzz

@YukioZzz YukioZzz commented Sep 28, 2026 •

Copy link
Copy Markdown

Problem

With a discovery connector selected, an explicit kv-transfer-config currently overrides the generated discovery configuration. For example, a MultiConnector containing MoRIIO and CPU offload reaches vLLM without the MoRIIO child's worker-specific addresses and allocated ports.

Changes

  • Resolve explicit JSON objects or strings through the existing backend resolver. Accept kv-transfer-config or kv_transfer_config, reject both together, and emit one bound CLI flag. Copy the template, locate exactly one connector matching the selected discovery table row, and bind its role and runtime topology.
  • Preserve sibling connectors, failure policies and transport options. Reject missing/ambiguous discovery children and conflicting roles or bindings when the worker command is built. Accept matching integer or string port values while retaining allocator-owned values in the output. Non-discovery configuration precedence is unchanged.
  • Document template usage with the existing MoRIIO discovery recipe and add command-rendering regression tests. The separate CPU-offload example and its generated snapshot have been removed as requested in review.

Before: the explicit MoRIIO child contains only recipe-supplied options such as backend: rdma. After: the same child also receives the router address, worker address/HTTP port, allocated handshake/notify ports and existing READ-mode setting; the CPU-offload child stays unchanged.

No new schema fields, router behavior, vLLM engine changes, or transport tuning are introduced. Connector selection still follows the existing table; topology binding reuses the existing allocator and discovery mapping.

The connector contract was checked against vLLM 387bcd39714c: moriio_common.py consumes the discovery fields, and multi_connector.py constructs children from kv_connector_extra_config.connectors. The documentation snippet requires an image that supports the supplied connectors and fields; this PR does not add support for other discovery protocols.

Validation

  • Rebased onto main at c2d437c10bca to include the launch-snapshot tooling.

  • make snapshots removed the deleted example's snapshot; make snapshots-check passed. There is no net example, snapshot, or example-inventory diff against main.

  • make check at 683c7f9c2951, including the alias/port review fixes: 3449 passed, 2 skipped, 6 deselected, including Ruff, blocking type checks and schema-documentation checks. These fixes were validated with CPU-only checks; no new cluster job was submitted.

  • srtctl dry-run -f examples/vllm/vllm-router-moriio-disagg.yaml passed. Schema documentation is unchanged and its freshness check passed.

  • All 24 dedicated template regressions pass; the combined template/router/connector/allocator suite passes all 67 tests. Coverage includes both argument spellings, duplicate-alias rejection, JSON/object inputs, input immutability, nested templates, sibling preservation, matching string/integer ports, conflicting bindings, malformed chains, and unchanged non-discovery precedence. Binding and conflict checks run when each worker command is built, not as comprehensive pre-submit template validation.

  • Earlier documentation-to-launch checks at 51cee8904a0b and its conflict-free merge with main at 12089b15ebbf passed for JSON object/string inputs with colocated 1P1D and 2P2D. The native mock orchestrator produced independent per-worker listener ports and preserved sibling connectors and transport options. These checks predate the alias/port review fixes.

  • Earlier real-weight GPU integration at 51cee8904a0b: two-node 1P1D, TP8/DCP8 per role, prefill MultiConnector with MoRIIO and SimpleCPUOffload, and direct MoRIIO on decode. The unmodified native orchestrator supplied discovery bindings absent from the input template; the sibling connector and transport options were preserved. This GPU run predates the alias/port review fixes and was not repeated for this revision.

  • Routed requests: 394/394 succeeded, with nonempty HTTP 200 completions, covering one cold request, four serial requests and a 120-second concurrency-8 window. Decode external-prefix-hit counters increased by 1,014,535 tokens. No serving-time RDMA flush, memory-registration failure or engine fatal error was observed.

The GPU evidence validates discovery binding and the routed request path only. It is not a qualification of shutdown behavior, accuracy, throughput, long-duration stability, CPU-offload eviction/reload, or other discovery protocols.

中文

修复显式 kv-transfer-config 遮蔽自动 discovery 配置的问题:后端在模板副本中定位唯一匹配的 connector,注入当前 worker 的角色、地址和已分配端口,保留 CPU offload 等兄弟 connector 及原有传输选项,并拒绝歧义或冲突配置。支持连字符和下划线两种参数写法,只输出一个完成绑定的 CLI 参数,同时设置两种写法会报错;匹配的整数或字符串端口均可接受,输出仍使用 allocator 的值。

按 review 要求移除独立 CPU-offload 示例及其生成快照,保留 YAML 文档片段、已有 discovery 示例引用及 24 项模板回归测试。未增加 schema 字段,未修改 router、vLLM 引擎或传输调优逻辑。绑定与冲突检查发生在 worker 命令生成时,不是完整的提交前模板验证。

本轮别名和端口修复后的 make check 为 3449 项通过、2 项跳过、6 项 integration 测试未选中;定向测试 67 项通过。静态检查、类型检查、schema 文档检查、已有 discovery 示例 dry-run 和快照检查均通过。本轮仅进行 CPU 验证,没有提交新的集群任务。相对 PR 基线,示例、快照和示例清单均无变化。

此前在 51cee8904a0b 及其与 main 12089b15ebbf 的无冲突合并版本上,验证了文档 YAML 到原生 mock 启动命令的完整路径:JSON 对象/字符串两种输入,各覆盖同节点 1P1D、2P2D,确认 worker 监听端口独立且兄弟 connector 不变。该项补充验证早于本轮别名和端口修复。

此前在 51cee8904a0b 上完成双节点真实权重 1P1D 集成验证:P/D 均为 TP8/DCP8,P 使用 MoRIIO 与 SimpleCPUOffload 组成的 MultiConnector,D 使用直接 MoRIIO。原生编排正确注入 discovery 配置并保留兄弟 connector;冷请求、串行请求及 120 秒并发 8 共 394/394 成功,decode 外部命中计数增加 1,014,535 token,服务期间未观察到 RDMA flush、内存注册失败或引擎致命错误。本轮别名和端口修复未重复 GPU 实验。

GPU 证据仅验证 discovery 绑定和路由请求路径,不构成退出行为、精度、吞吐、长时间稳定性、CPU offload 驱逐回载或其他 discovery 协议的验证。

@cquil11

cquil11 commented Sep 29, 2026

Copy link
Copy Markdown
Contributor

this makes sense. the current design isn't my favorite approach because it feels like it's not extensible. but I can't see a better way of doing right now

@cquil11

cquil11 commented Sep 29, 2026

Copy link
Copy Markdown
Contributor

actually on secodn thought, this isn't specific to just mori it will work for any discovery connector. so I like it

@cquil11

cquil11 commented Sep 29, 2026

Copy link
Copy Markdown
Contributor

@YukioZzz can you run make snapshots and commit+push the files please?

YukioZzz added a commit to SemiAnalysisAI/InferenceX that referenced this pull request Sep 29, 2026
临时携带 NVIDIA/srt-slurm#508 在 dc1e825d 的完整补丁,为显式 MoRI/MultiConnector 注入运行时 discovery 地址。依赖 pin 包含该 PR 后删除本提交;不更换依赖仓库,不重复携带已合入的 #504。
YukioZzz added a commit to SemiAnalysisAI/InferenceX that referenced this pull request Sep 29, 2026
临时携带 NVIDIA/srt-slurm#508 在 dc1e825d 的完整补丁,为显式 MoRI/MultiConnector 注入运行时 discovery 地址。依赖 pin 包含该 PR 后删除本提交;不更换依赖仓库,不重复携带已合入的 #504。
YukioZzz added a commit to SemiAnalysisAI/InferenceX that referenced this pull request Sep 29, 2026
临时携带 NVIDIA/srt-slurm#508 在 dc1e825d 的完整补丁,为显式 MoRI/MultiConnector 注入运行时 discovery 地址。依赖 pin 包含该 PR 后删除本提交;不更换依赖仓库,不重复携带已合入的 #504。
@YukioZzz

Copy link
Copy Markdown
Author

@YukioZzz can you run make snapshots and commit+push the files please?

ok, working on it now~

@YukioZzz
YukioZzz force-pushed the yichaozhu/discovery-connector-templates branch from dc1e825 to 949a892 Compare September 29, 2026 15:35
@YukioZzz

YukioZzz commented Sep 29, 2026 •

Copy link
Copy Markdown
Author

Done, thanks! Rebased onto main and ran make snapshots; the new offload example's launch snapshot is committed in 949a892. Existing snapshots are unchanged, and make snapshots-check passes.

I also clarified the template-loading code and documentation, added regression coverage, and updated the example inventory. make check passes: 3446 passed, 2 skipped, 6 deselected. Validation was CPU-only; no cluster job was submitted.

@cquil11

cquil11 commented Sep 29, 2026

Copy link
Copy Markdown
Contributor

@YukioZzz can you remove examples/vllm/vllm-router-moriio-offload.yaml pls?

@YukioZzz

Copy link
Copy Markdown
Author

@YukioZzz can you remove examples/vllm/vllm-router-moriio-offload.yaml pls?

I see, got it. It it not necessarily needed.

@YukioZzz
YukioZzz force-pushed the yichaozhu/discovery-connector-templates branch from 949a892 to 51cee89 Compare September 29, 2026 16:22
@YukioZzz

YukioZzz commented Sep 29, 2026 •

Copy link
Copy Markdown
Author

Done, removed examples/vllm/vllm-router-moriio-offload.yaml and regenerated snapshots to remove its launch snapshot. The example inventory is also restored, so there is no net change to examples, snapshots, or tests/test_e2e.py against main.

The PR now contains only the discovery-template fix, its 16 regression tests, and documentation pointing to the existing MoRIIO discovery recipe. The implementation is unchanged from the previous revision.

make check passes: 3441 passed, 2 skipped, 6 deselected. make snapshots-check and the existing discovery recipe's dry-run also pass.

Additional real-weight GPU integration at unchanged HEAD 51cee8904a0b completed 394/394 successful routed requests in a two-node 1P1D configuration, covering a cold request, serial requests and a 120-second concurrency-8 window. The native orchestrator correctly injected discovery bindings absent from the input template and preserved the sibling connector; decode external-prefix-hit counters increased by 1,014,535 tokens.

This integration evidence validates discovery binding and the routed request path only; it does not qualify shutdown behavior, accuracy, performance, long-duration stability or CPU-offload eviction/reload. The PR description includes the additional mock and main-compatibility validation results.

@codecov-commenter

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (main@c2d437c). Learn more about missing BASE report.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #508   +/-   ##
=======================================
  Coverage        ?   83.40%           
=======================================
  Files           ?      154           
  Lines           ?    22158           
  Branches        ?        0           
=======================================
  Hits            ?    18481           
  Misses          ?     3677           
  Partials        ?        0           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ishandhanani ishandhanani added devin and removed devin labels Sep 30, 2026

@devin-ai-integration devin-ai-integration 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.

Reviewed against REVIEW.md and the Design Rules. The fix goes through the existing resolver (kv_transfer_config), reads the table row (row.discovery, row.kv_connector) rather than a connector name, gets its ports from the allocator, and cites upstream at 387bcd39714c. Tests cover the new behavior well, and since no example changed, the launch snapshots show no diff.

0 blocking, 4 nits (inline).

Checks run locally at 51cee89: make lint passes. tests/test_discovery_connector_templates.py, test_vllm_router_frontend.py, test_vllm_connectors.py, test_vllm_port_allocation.py and test_launch_snapshots.py pass (88/88).

Comment thread src/srtctl/backends/vllm.py Outdated
)
payload = row.transfer_config(mode)
payload["kv_connector_extra_config"] = self._discovery_extra_config(process, runtime)
template = self.get_config_for_mode(mode).get("kv-transfer-config")

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.

Nit: This only reads the hyphenated key. _config_to_cli_args maps _ to -, so roles.prefill.args.kv_transfer_config: {...} skips the template and renders a second, unbound --kv-transfer-config. The flags are sorted, so the unbound one comes last and argparse keeps it, which is the bug this PR fixes, still reachable through the other spelling. I reproduced this with the test's _command helper: the output has two --kv-transfer-config flags, and the second has no host_ip/ports. The Dynamo path at L1750 already treats both spellings as explicit. Suggest popping either spelling here (and in build_worker_command), or rejecting the underscore one. No recipe uses that spelling today, hence a nit.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed. The discovery resolver now accepts either argument spelling, and the command builder removes the underscore alias before emitting one bound --kv-transfer-config. Supplying both spellings is rejected rather than relying on flag ordering. Regression coverage exercises both spellings with object/string templates and checks that only one flag is emitted, sibling connectors are preserved, and the input is unchanged.

for child in children:
visit(child)

visit(payload)

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.

Nit: A template with no or duplicate MoRIIOConnector, or the wrong kv_role, is a static recipe error. Right now it only raises in build_worker_command, after the allocation is granted, and srtctl dry-run doesn't catch it. You could split the structural half (parse, find the unique target, check the role) into a helper and call it from VLLMRouterFrontend.validate, so dry-run rejects it before submit. The topology-conflict check can stay here. The PR description already calls this out, so this could be a follow-up.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Agreed that earlier structural validation would be useful. I am leaving that for a follow-up as suggested, keeping parsing, target matching, and role checks in the existing backend resolver in this PR. The documentation now explicitly says validation happens when the worker command is built; it does not claim that dry-run rejects malformed templates before submission.

Comment thread src/srtctl/backends/vllm.py Outdated
target["kv_role"] = expected_role
extra = target.setdefault("kv_connector_extra_config", {})
for key, value in self._discovery_extra_config(process, runtime).items():
if key in extra and extra[key] != value:

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.

Nit: The comparison is type-strict. _discovery_extra_config emits ports as strings, so a YAML object template that sets http_port: 6101 (an int, matching the allocation) is rejected as a conflict. The docs discourage hard-coding these, so this is minor. Comparing str(extra[key]) != str(value) for the port keys, or noting in the error that values must be strings, would avoid a confusing failure.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed. Matching integer port values are normalized for comparison with the allocator's strings; the rendered config retains the allocator's string values. This is limited to port keys: mismatched ports, floats, and booleans remain rejected. Tests cover matching string/integer ports and conflicting values without mutating the input template.

Comment thread docs/vllm-router.md Outdated
```

The pinned vLLM image must support the supplied connectors and their fields.
This changes command rendering only; it does not change Router or engine code.

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.

Nit: "This changes command rendering only; it does not change Router or engine code." describes the PR, not the current behavior (docs/AGENTS.md: docs describe the implementation). Suggest dropping it and keeping the image-support sentence. Also, "rejected before worker launch" (L192) could say "when the worker command is built" to match where the check actually runs.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Updated as suggested: removed the PR-scope sentence, retained the image-support requirement, and changed the validation timing to "when the worker command is built." The section also documents the accepted argument spellings and port value types.

Resolve explicit discovery templates through the existing backend resolver. Bind the unique matching connector to the allocated worker topology while preserving sibling connectors, transfer options and non-discovery precedence.

Add command-rendering regression tests and document template usage with the existing discovery recipe.

Signed-off-by: Yichao Zhu <Yichao.Zhu@amd.com>
@YukioZzz
YukioZzz force-pushed the yichaozhu/discovery-connector-templates branch from 51cee89 to 683c7f9 Compare September 30, 2026 04:43
@YukioZzz

Copy link
Copy Markdown
Author

@cquil11 Addressed the alias handling, equivalent integer ports, and documentation comments in 683c7f9, folded into the existing single signed-off commit. Earlier structural validation during dry-run remains a follow-up as suggested; this revision does not change frontends or lifecycle handling.

make check passes: 3449 passed, 2 skipped, 6 deselected. All 24 template regressions pass, as do the existing discovery recipe's dry-run and make snapshots-check; examples and snapshots have no net diff. The PR description separates these CPU checks from the earlier GPU request-path evidence at 51cee890.

The updated CI and copyright check require workflow approval. Could you approve the runs and take another look when convenient? Once checks pass, this is ready for merge from my side.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants