Skip to content

fix(trtllm): forward routing.priority to the engine, mapped into range - #30

Open
sopwg612 wants to merge 2 commits into
feat-deepinfra-runtime-07-09from
feat-trtllm-routing-priority-v2
Open

fix(trtllm): forward routing.priority to the engine, mapped into range#30
sopwg612 wants to merge 2 commits into
feat-deepinfra-runtime-07-09from
feat-trtllm-routing-priority-v2

Conversation

@sopwg612

@sopwg612 sopwg612 commented Aug 11, 2026

Copy link
Copy Markdown

The gap

Two upstream changes never met:

So trtllm reads:

priority = request.get("priority", DEFAULT_REQUEST_PRIORITY)   # top level

while every other adapter reads routing:

adapter reads
vllm handlers.py routing.get("priority", 0)
sglang prefill_handler.py routing.get("priority")
sglang decode_handler.py (request.get("routing") or {}).get("priority")
trtllm request.get("priority", ...) ← top level

PreprocessedRequest has no top-level priority field, so real traffic always falls through to DEFAULT_REQUEST_PRIORITY and per-request priority never reaches the engine. That's the behaviour the docs record as "TensorRT-LLM: per-request engine scheduling priority is not currently exposed through Dynamo."

The fix

Top-level read stays first, so the canary pin from ai-dynamo#8488 still wins. routing.priority becomes the fallback beneath it. routing is already in scope — bound twelve lines up for dp_rank.

Why mapped, not passed through

routing.priority is dynamo's unbounded, higher-is-urgent scale. GenerationRequest.__init__ validates a float in [0.0, 1.0] (tensorrt_llm/executor/request.py). Passing the raw value collides with that validator.

clamp(0.5 + 0.1 * p) is the map deepapi already uses for its aggregated pytrtllm path, sign pre-flipped:

routing.priority engine
0 0.5 (engine default)
1 0.6
2 0.7
≥5 1.0

Per-engine conversion in the adapter is the established pattern here — vllm negates for its lower-is-urgent convention, sglang does int() plus a guard on the inverting flag.

Requires

scheduler_config.waiting_queue_policy=priority on the worker. Under the default FCFS waiting queue TRT-LLM logs "the priority value will be ignored" and discards it.

Testing

All 49 tests in test_trtllm_handler_base.py pass on GPU (L40S), run inside
the image the prod workers actually use
(dynamo-trtllm-runtime:07-09-62fb5b6f-...) with this branch's
components/src/dynamo/trtllm mounted over the installed package. The nine
TestHealthCheckPriority cases are confirmed individually as PASSED, not
skipped -- the class is async, so it needs pytest-asyncio plus the repo's
asyncio_mode=auto, without which pytest silently skips the whole class.

Added: parametrized mapping (1→0.6, 2→0.7, 5→1.0, 50→1.0, 0→0.5), and that the health-check top-level pin beats a conflicting routing.priority.

Second commit: greening the branch CI

pre-commit/action runs --all-files, so every PR against
feat-deepinfra-runtime-07-09 inherited the branch's own lint debt: checking out
the branch tip with zero PR changes applied fails isort, black, ruff and the
pytest-marker report, and pre-merge-status-check then goes red by aggregation.
That buries any real finding a feature PR might introduce, so the fix rides
along here (originally split out as #31, now folded in at your request).

  • isort / black over 8 planner modules and trtllm/publisher.py.
  • ruff — all four findings were in
    container/deps/trtllm/patches/v1.3.8/py_executor.py (F821 Undefined name 'ray', E712 == False). That is a verbatim snapshot of upstream TRT-LLM
    source that a Dockerfile COPYs over the installed package, maintained by
    diffing against upstream — reformatting it destroys the diff, and its findings
    are upstream's code. So container/deps/.*/patches/.* joins the existing
    top-level exclude, which already covers *.patch; these are the same thing
    kept as .py.
  • Report pytest markers — the standard planner block
    pytestmark = [gpu_0, pre_merge, unit, planner] added to the four unit test
    files lacking it, matching ~10 siblings that already carry it. Clears all 65
    missing marker sets. test_num_req_gate.py also needed import pytest,
    placed above its deliberate prometheus_names compatibility shim so the shim
    and its trailing late import stay intact.

Formatting only — verified, not asserted. Every touched file's AST was
dumped before and after and compared: 11 of 12 identical; rust_adapter.py
differs only because isort reorders two stdlib imports (identical import set,
identical non-import AST, zero executable statements interleaved among them);
the four test files differ by exactly the added pytestmark node.

pre-commit run --all-files now passes clean on this branch, and the same
config verified green in CI on #31 (pre-commit pass, pre-merge-status-check
pass) before being folded in here.

Still red, not fixable by code

  • copyright-checks dies at container init: docker pull ghcr.io/deepinfra/dynamo/helm-tester:0.1.1manifest unknown on this fork,
    so the header script never runs. Fails on every deepinfra/dynamo PR regardless
    of content.
  • lychee — pre-existing broken links in NVIDIA's upstream docs.

Both were documented the same way in #26.

Related

Supersedes #28 (reverted by #29) — same read, but with the range mapping that #28 was missing. Absorbs #31 (branch CI cleanup), which is closed in favour of the second commit here. Companion deepinfra/backend PR ai-dynamo#3982 emits the header.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QqzQrZR2qrvxM6DsxqGciu

The trtllm handler reads priority off the top level of the request. That key is
the canary health-check pin from ai-dynamo#8488 and nothing else sets it -- the Rust
frontend puts per-request priority at routing.priority, which ai-dynamo#7492 wired for
vllm and sglang but never for trtllm. So every real request fell through to
DEFAULT_REQUEST_PRIORITY and per-request priority never reached the engine,
which is the behaviour the docs record as "not currently exposed through
Dynamo" for TensorRT-LLM.

Keep the top-level read first so the canary pin still wins, and fall back to
routing.priority beneath it. routing is already in scope from the dp_rank
lookup twelve lines up.

The value is mapped rather than passed through: routing.priority is dynamo's
unbounded higher-is-urgent scale, while GenerationRequest validates a float in
[0.0, 1.0] (tensorrt_llm/executor/request.py). clamp(0.5 + 0.1 * p) puts 1 at
0.6 and saturates at 5, matching the map deepapi already uses for its
aggregated pytrtllm path. An earlier attempt passed the raw value and collided
with that validator.

vllm and sglang need nothing -- both already read routing.priority, and sglang
normalizes in its own adapter the same way.

NOT RUN: tensorrt_llm is not importable on the host these were written on, and
the test module skips without CUDA. The new tests need a GPU build container.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QqzQrZR2qrvxM6DsxqGciu
@sopwg612

Copy link
Copy Markdown
Author

CI note — the three red checks are pre-existing fork infrastructure/lint noise, not this change:

  • copyright-checks — the job container can't be pulled: docker pull ghcr.io/deepinfra/dynamo/helm-tester:0.1.1manifest unknown, three retries, then abort. It never reaches any file in this PR.
  • pre-commitisort/black/ruff reformat components/src/dynamo/planner/core/perf_model/rust_adapter.py, components/src/dynamo/planner/tests/unit/test_confirm_proposal.py, and the vendored container/deps/trtllm/patches/v1.3.8/py_executor.py. This PR touches none of them. The "Report pytest markers" hook reports 65 missing marker sets repo-wide, all in planner tests.
  • lychee — link checker, unrelated.

Running pre-commit locally against only this PR's two files passes every formatting hook (isort, black, flake8, ruff, codespell, whitespace/EOL) and produces zero marker violations for test_trtllm_handler_base.py — the module-level pytestmark covers the new cases.

The already-merged #29 shows the same three failures on the same base branch, which is the confirmation that this is the branch's steady state rather than a regression here.

@sopwg612

Copy link
Copy Markdown
Author

Follow-up with the decisive test, since "same failures as #29" was only circumstantial.

pre-commit/action@v3.0.1 runs pre-commit run --all-files, so the job lints the whole tree rather than this PR's diff. I checked out the base branch tip (e5c289605, containing none of this PR's changes) and ran pre-commit run --all-files locally. It fails on exactly the same four hooks:

isort .................. Failed
black .................. Failed
ruff ................... Failed
Report pytest markers .. Failed

modifying 15 files — components/src/dynamo/planner/** (10), components/src/dynamo/trtllm/publisher.py, and container/deps/trtllm/patches/v1.3.8/{handler_base,llm_worker,py_executor}.py — plus 65 missing marker sets, all in planner tests. None of those are in this PR.

pre-merge-status-check is red only because it aggregates: needs: [changed-files, pre-commit, fern-check, ...]. copyright-checks aborts before linting anything (docker pull ghcr.io/deepinfra/dynamo/helm-tester:0.1.1manifest unknown). lychee is the link checker.

So this PR cannot turn those green by changing anything in this PR — it needs a separate branch-wide formatting cleanup. Flagging rather than folding a 15-file reformat of vendored TRT-LLM patch files into a 2-file behavior change.

@sopwg612

Copy link
Copy Markdown
Author

Fixed, in #31 rather than here.

The red checks were the branch's, not this PR's — pre-commit/action runs --all-files, so feat-deepinfra-runtime-07-09's own lint debt showed up on every PR against it. #31 clears it: isort/black over the planner modules, container/deps/**/patches/ excluded from linting (verbatim upstream snapshots — all four ruff findings were upstream's code), and the standard pytestmark block added to the four planner test files missing it, clearing all 65 marker sets.

#31's CI: pre-commit pass, pre-merge-status-check pass. Four red checks down to two.

I also verified this PR specifically: cherry-picking 1750f19d onto #31's branch and running pre-commit run --all-files passes clean with zero files modified. So once #31 merges and this rebases, the only red left here is copyright-checks (can't pull ghcr.io/deepinfra/dynamo/helm-tester:0.1.1 — fails on every PR in this fork) and lychee (pre-existing upstream doc links), the same two #26 documented as unfixable.

Merge order: #31 first, then rebase this.

pre-commit/action runs --all-files, so every PR against this branch
inherits its lint state -- isort, black, ruff and the pytest-marker
report have all been red on the branch tip itself, which buries any
real finding a feature PR might introduce.

- isort/black over 8 planner modules plus trtllm/publisher.py.
- Exclude container/deps/**/patches/ . Those are verbatim snapshots of
  upstream engine source that a Dockerfile COPYs over the installed
  package; they are maintained by diffing against upstream, so
  reformatting them destroys the diff. All four ruff findings were in
  that tree and are upstream's code, not ours.
- Add the standard planner pytestmark block to the four unit test files
  that lacked it, clearing all 65 missing marker sets.

Formatting only: the AST of every touched file is unchanged, except
rust_adapter.py where isort reorders two stdlib imports (same import
set, same non-import AST, no executable code interleaved) and the four
test files which gain exactly the pytestmark node.

Signed-off-by: Sihan Wang <sihan@deepinfra.com>
@sopwg612
sopwg612 had a problem deploying to external_collaborator August 12, 2026 22:33 — with GitHub Actions Failure
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.

1 participant