Skip to content

[None][feat] support NIXL cache transceiver with Ray - #17295

Merged
chuangz0 merged 8 commits into
NVIDIA:mainfrom
chuangz0:ray_support_nixl_cache_transceiver
Aug 12, 2026
Merged

[None][feat] support NIXL cache transceiver with Ray#17295
chuangz0 merged 8 commits into
NVIDIA:mainfrom
chuangz0:ray_support_nixl_cache_transceiver

Conversation

@chuangz0

@chuangz0 chuangz0 commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • support NIXL cache-transceiver rank discovery and metadata exchange with the Torch process group used by Ray
  • remove the undocumented TRTLLM_NIXL_PORT fixed-port override; NIXL listeners now always select an available port
  • support both CPP and PYTHON cache-transceiver runtimes in the Ray disaggregated-serving example
  • re-enable the existing tp1/tp2 Ray disaggregated-serving coverage and add matching Python-runtime coverage
  • preserve access to internal libraries when packaging the NIXL wrapper so transfer-agent stub generation works without environment-specific library paths
  • share one AwaitResponseHelper.process_responses() implementation between regular and Ray RPC workers

Why

The NIXL transfer agent and agent connection manager assumed MPI for rank discovery and collective metadata exchange. Ray workers disable MPI and use a Torch process group, so NIXL cache transfer could not initialize correctly in that environment. In addition, the tp1 test was skipped under an unrelated bug and tp2 remained waived.

The undocumented TRTLLM_NIXL_PORT override was removed intentionally. Its rank-derived fixed-port scheme was not safe across independent context and generation sessions, where session-local ranks can overlap. NIXL listeners now always select an available port and advertise the selected endpoint through exchanged agent metadata.

Local-address selection is also an intentional behavior change for all NIXL deployments, not only the Ray/Torch process-group path. All listening NIXL agents now use the shared common::getLocalIp() selection with TRTLLM_NIXL_INTERFACE as the explicit override; when no interface is configured, the shared default-route/hostname-based selection is used. IPv6 literals are advertised as [address]:port so the address and dynamically selected port remain unambiguous.

The Python-transceiver first-token flow can produce an empty response (None) for an iteration with no client-visible serialized result. The regular worker path already runs engine responses through _engine_response_callback, filters non-client responses, and appends deferred submission errors before IPC handling. RpcWorkerMixin.fetch_responses() bypassed that existing preprocessing and passed the raw None to IPC, where response.has_error() terminated the Ray RPC stream.

The existing callback/filter/deferred-error logic is factored into AwaitResponseHelper.process_responses(). Both the regular worker and Ray RPC worker call that shared function before responses_handler(). No PyExecutor or placement-group behavior is changed by this fix.

This follows the intent of #10259 while adapting it to the current cache-transceiver and ProcessGroup implementation.

Validation

  • signed-off commit hooks passed, including formatting, lint, YAML/test-list validation, DCO, pre-push pre-commit update, and confidentiality scan
  • clean full Release SM86 build from a new build directory completed, including the main bindings, libtensorrt_llm.so, NIXL wrapper, transfer-agent binding, executor, and UCX wrapper
  • nanobind stub generation completed as part of the clean build
  • a 581 MB wheel was built and installed into an isolated temporary directory with --no-deps
  • the installed wheel's NIXL wrapper has RUNPATH=$ORIGIN:$ORIGIN/nixl/, and ldd resolves libpg_utils.so from the same wheel
  • bare transfer-agent binding import and package import from the isolated wheel passed
  • isolated-wheel NIXL transfer-agent binding tests: 5 passed
  • isolated-wheel single-process Python cache-transceiver test: 1 passed
  • isolated-wheel NIXL initialization through a singleton Torch ProcessGroup passed with MPI disabled
  • Ray RPC preprocessing and event-loop error-broadcast tests: 7 passed
  • local final-code validation: CPP-runtime and PYTHON-runtime tp1 disaggregated-serving E2E each completed five concurrent requests; every request returned 32 completion tokens, and the existing disaggregated-test accuracy checks (The capital of Germany is Berlin, Asyncio is a Python library, and no Berlin Berlin) passed, with no NoneType.has_error, RPCStreamingError, or ray_executor_main_loop failure; context/generation shared one physical RTX A6000 through a temporary fractional placement adjustment that is not part of this PR

The B200/B300 tp1/tp2 CPP/PYTHON E2E cases should be rerun in CI with the final narrowed diff.

Dev Engineer Review

  • Adds Ray/Torch process-group rank and world-size discovery for NIXL cache agents.
  • Adds optional rank and world_size fields to BaseAgentConfig and both Python and C++ NIXL agent wrappers.
  • Adds MPI and single-process fallbacks.
  • Adds IPv6 address parsing and formatting.
  • Updates Ray examples to support C++ and Python transceiver runtimes.
  • Shares response preprocessing between regular workers and Ray RPC workers.
  • Review points remain for address-format versioning, mixed-version upgrades, IPv6 edge cases, discovery failures, and isolated libtorch packaging.
  • The new local-address selection should remain limited to the Ray/Torch process-group path unless the MPI behavior change is intentional.
  • The test-list entries and waiver removal match the added Ray coverage.

QA Engineer Review

  • Added test_ray_disaggregated_serving_python.
  • Refactored test_ray_disaggregated_serving to use runtime parameters.
  • Added concurrent HTTP response validation for Ray disaggregated serving.
  • Added RpcWorkerMixin.fetch_responses unit coverage.
  • Expanded BaseAgentConfig binding tests.
  • Added Python-agent topology tests.
  • Added C++ binding topology-forwarding tests.
  • Added the RPC worker unit test to l0_cpu.yml.
  • Added Python Ray coverage to l0_dgx_b200.yml and l0_dgx_h100.yml.
  • Removed the skipped tp2 Ray test from waives.txt.
  • Coverage is represented in CI test lists. Verdict: sufficient.

@chuangz0
chuangz0 force-pushed the ray_support_nixl_cache_transceiver branch 3 times, most recently from 0b89b30 to dd29ae5 Compare August 5, 2026 09:49
@chuangz0
chuangz0 marked this pull request as ready for review August 5, 2026 09:51
@chuangz0
chuangz0 requested review from a team as code owners August 5, 2026 09:51
@chuangz0

chuangz0 commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

The PR adds MPI and Torch process-group topology discovery for NIXL cache agents, supports CPP or PYTHON Ray transceiver runtimes, centralizes RPC response processing, and expands unit and integration coverage.

Changes

Cache transport runtime support

Layer / File(s) Summary
Process-group rank and agent-state exchange
cpp/include/tensorrt_llm/executor/transferAgent.h, cpp/tensorrt_llm/executor/cache_transmission/agent_utils/*
Agent connections store rank and world size, discover topology through MPI or Torch process groups, exchange agent state through the selected collective, and use stored rank values for logging.
NIXL agent initialization and addressing
cpp/tensorrt_llm/executor/cache_transmission/nixl_utils/*, tensorrt_llm/_torch/disaggregation/native/transfer.py, tensorrt_llm/_torch/disaggregation/nixl/*, tests/unittest/bindings/*, tests/unittest/disaggregated/test_agent.py
NIXL configuration and agents accept topology values. Initialization validates them, derives defaults, allocates rank-aware ports, discovers local addresses, and parses IPv4 or bracketed IPv6 endpoints.
Ray runtime selection and integration coverage
examples/ray_orchestrator/disaggregated/*, tests/integration/defs/examples/test_ray.py, tests/integration/test_lists/*
The serving script selects CPP or PYTHON NIXL runtimes. Documentation and integration tests cover both runtimes with concurrent completion validation.

RPC response processing

Layer / File(s) Summary
Shared response processing
tensorrt_llm/executor/base_worker.py, tensorrt_llm/executor/rpc_worker_mixin.py
AwaitResponseHelper.process_responses() centralizes callback filtering and nonblocking temporary-error draining. fetch_responses uses the helper before invoking the response handler.
RPC response validation
tests/unittest/executor/test_rpc_worker_mixin.py, tests/integration/test_lists/test-db/l0_cpu.yml
CPU-only tests verify timeout propagation, callback handling, temporary errors, handler output, and returned responses.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant AgentConnectionManager
  participant PgHelper
  participant NixlTransferAgent
  participant RemoteAgent
  AgentConnectionManager->>PgHelper: Discover rank and world size
  AgentConnectionManager->>NixlTransferAgent: Initialize with topology values
  NixlTransferAgent->>NixlTransferAgent: Allocate port and format local address
  NixlTransferAgent->>RemoteAgent: Parse endpoint and connect
Loading

Possibly related PRs

Suggested reviewers: bowenfu, brnguyen2, shixiaowei02

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 24.24% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
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.
Title check ✅ Passed The title clearly identifies the feature: NIXL cache-transceiver support for Ray.
Description check ✅ Passed The description explains the problem, solution, behavior changes, and validation with relevant build, unit, and integration test results.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

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

🧹 Nitpick comments (2)
tests/integration/defs/examples/test_ray.py (1)

71-78: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add annotations and docstrings to the new test functions.

Add precise parameter types and -> None return types. Add Google-style docstrings for test_ray_disaggregated_serving_python and _run_ray_disaggregated_serving.

As per coding guidelines: “Annotate every function” and “use Google-style docstrings for classes and functions.”

🤖 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 `@tests/integration/defs/examples/test_ray.py` around lines 71 - 78, Add
precise type annotations, including -> None, to
test_ray_disaggregated_serving_python and _run_ray_disaggregated_serving. Add
concise Google-style docstrings to both functions documenting their purpose and
each parameter, using the existing parameter names and types.

Source: Coding guidelines

tests/unittest/executor/test_rpc_worker_mixin.py (1)

55-64: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Add coverage for the empty-response stream path.

Test coverage summary:

  • Added: test_fetch_responses_processes_and_filters_engine_responses.
  • Modified: none.
  • Removed: none.
  • CI list: tests/integration/test_lists/test-db/l0_cpu.yml includes this test file.
  • Manual QA list: not applicable for this CPU-only unit test.
  • Verdict: needs follow-up.

The test covers timeout propagation, callback filtering, temporary errors, and queue delivery. It does not verify an empty Python-transceiver response through fetch_responses_loop_async() and confirm that polling continues until shutdown. Add that regression case.

As per path instructions, test-code changes under tests/** require changed-test, test-list, and coverage reporting. The PR objective identifies empty Python-transceiver responses as the regression target.

🤖 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 `@tests/unittest/executor/test_rpc_worker_mixin.py` around lines 55 - 64, Add a
regression test alongside
test_fetch_responses_processes_and_filters_engine_responses that exercises an
empty Python-transceiver response through fetch_responses_loop_async(), verifies
polling continues rather than terminating on the empty response, and confirms
the loop exits only after shutdown. Update the required changed-test, test-list,
and coverage reporting for this tests/** change.

Source: Path instructions

🤖 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 `@tensorrt_llm/executor/base_worker.py`:
- Around line 1125-1126: Update the temp_error_responses drain in
process_responses() to repeatedly call get_nowait() and catch queue.Empty to
terminate the loop. Remove the empty() check and blocking get() pattern,
preserving response collection while remaining safe for concurrent callers.

---

Nitpick comments:
In `@tests/integration/defs/examples/test_ray.py`:
- Around line 71-78: Add precise type annotations, including -> None, to
test_ray_disaggregated_serving_python and _run_ray_disaggregated_serving. Add
concise Google-style docstrings to both functions documenting their purpose and
each parameter, using the existing parameter names and types.

In `@tests/unittest/executor/test_rpc_worker_mixin.py`:
- Around line 55-64: Add a regression test alongside
test_fetch_responses_processes_and_filters_engine_responses that exercises an
empty Python-transceiver response through fetch_responses_loop_async(), verifies
polling continues rather than terminating on the empty response, and confirms
the loop exits only after shutdown. Update the required changed-test, test-list,
and coverage reporting for this tests/** change.
🪄 Autofix

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: 3191efaa-20ad-4408-9daf-54e33603d284

📥 Commits

Reviewing files that changed from the base of the PR and between 9564b3b and dd29ae5.

📒 Files selected for processing (15)
  • cpp/tensorrt_llm/executor/cache_transmission/agent_utils/connection.cpp
  • cpp/tensorrt_llm/executor/cache_transmission/agent_utils/connection.h
  • cpp/tensorrt_llm/executor/cache_transmission/nixl_utils/CMakeLists.txt
  • cpp/tensorrt_llm/executor/cache_transmission/nixl_utils/transferAgent.cpp
  • cpp/tensorrt_llm/executor/cache_transmission/nixl_utils/transferAgent.h
  • examples/ray_orchestrator/disaggregated/disagg_serving_local.sh
  • scripts/build_wheel.py
  • tensorrt_llm/executor/base_worker.py
  • tensorrt_llm/executor/rpc_worker_mixin.py
  • tests/integration/defs/examples/test_ray.py
  • tests/integration/test_lists/test-db/l0_cpu.yml
  • tests/integration/test_lists/test-db/l0_dgx_b200.yml
  • tests/integration/test_lists/test-db/l0_dgx_h100.yml
  • tests/integration/test_lists/waives.txt
  • tests/unittest/executor/test_rpc_worker_mixin.py
💤 Files with no reviewable changes (1)
  • tests/integration/test_lists/waives.txt

Comment thread tensorrt_llm/executor/base_worker.py Outdated
@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #64023 [ run ] triggered by Bot. Commit: dd29ae5 Link to invocation

@chuangz0
chuangz0 force-pushed the ray_support_nixl_cache_transceiver branch from dd29ae5 to 760f0b9 Compare August 5, 2026 10:11
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@chuangz0
chuangz0 force-pushed the ray_support_nixl_cache_transceiver branch from 760f0b9 to 7a7ac50 Compare August 5, 2026 10:19
@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #64499 [ run ] completed with state SUCCESS. Commit: 36d82af
/LLM/main/L0_MergeRequest_PR pipeline #52372 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@chuangz0
chuangz0 force-pushed the ray_support_nixl_cache_transceiver branch 2 times, most recently from 00ddbe9 to 07fdc46 Compare August 10, 2026 02:10
@chuangz0

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #64919 [ run ] triggered by Bot. Commit: 07fdc46 Link to invocation

@chuangz0
chuangz0 force-pushed the ray_support_nixl_cache_transceiver branch from 07fdc46 to e583d1d Compare August 10, 2026 06:17
@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #64919 [ run ] completed with state SUCCESS. Commit: 07fdc46
/LLM/main/L0_MergeRequest_PR pipeline #52760 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

Comment thread tensorrt_llm/executor/rpc_worker_mixin.py Outdated
Comment thread examples/ray_orchestrator/disaggregated/disagg_serving_local.sh Outdated
@chuangz0

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #65186 [ run ] triggered by Bot. Commit: b31b08d Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #65186 [ run ] completed with state FAILURE. Commit: b31b08d
/LLM/main/L0_MergeRequest_PR pipeline #52976 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

Signed-off-by: Chuang Zhu <111838961+chuangz0@users.noreply.github.com>
Signed-off-by: Chuang Zhu <111838961+chuangz0@users.noreply.github.com>
Signed-off-by: Chuang Zhu <111838961+chuangz0@users.noreply.github.com>
…dback

Use RFC 3986 bracketed IPv6 literals for the NIXL agent address so IPv4
keeps the legacy ip:port format and stays compatible across versions.
Drain deferred error responses with get_nowait() to avoid blocking when
the ManagedThread and RPC fetch_responses() race on the same queue.
Document the NIXL backend and --transceiver_runtime option in the Ray
disaggregated-serving example README.

Signed-off-by: Chuang Zhu <111838961+chuangz0@users.noreply.github.com>
Signed-off-by: Chuang Zhu <111838961+chuangz0@users.noreply.github.com>
Signed-off-by: Chuang Zhu <111838961+chuangz0@users.noreply.github.com>
Signed-off-by: Chuang Zhu <111838961+chuangz0@users.noreply.github.com>
Signed-off-by: Chuang Zhu <111838961+chuangz0@users.noreply.github.com>
@chuangz0
chuangz0 force-pushed the ray_support_nixl_cache_transceiver branch from b31b08d to d07e811 Compare August 12, 2026 01:02
@chuangz0

Copy link
Copy Markdown
Collaborator Author

/bot run --stage-list "DGX_H100-PyTorch-6, RTXPro6000D-PyTorch-1, GB300-4_GPUs-PyTorch-1"

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #65439 [ run ] triggered by Bot. Commit: d07e811 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #65439 [ run ] completed with state FAILURE. Commit: d07e811
/LLM/main/L0_MergeRequest_PR pipeline #53190 (Partly Tested) completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@chuangz0

Copy link
Copy Markdown
Collaborator Author

/bot skip --comment "all test have passed"

@chuangz0
chuangz0 enabled auto-merge (squash) August 12, 2026 05:27
@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #65502 [ skip ] triggered by Bot. Commit: d07e811 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #65502 [ skip ] completed with state SUCCESS. Commit: d07e811
Skipping testing for commit d07e811

Link to invocation

@chuangz0
chuangz0 merged commit c357c95 into NVIDIA:main Aug 12, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants