Skip to content

refactor(router): unify classifier inputs; deprecate absolute busy thresholds - #16620

Merged
ishandhanani merged 4 commits into
idhanani/adm-4-reject-on-rowsfrom
idhanani/adm-5-on-full
Oct 29, 2026
Merged

ishandhanani merged 4 commits into
idhanani/adm-4-reject-on-rowsfrom
idhanani/adm-5-on-full

Conversation

@ishandhanani

@ishandhanani ishandhanani commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Part of #16543 (PR 5 of 5)

Summary

Unify classifier worker metadata and input sequence length naming with worker selection, and deprecate the absolute prefill busy thresholds.

Classifier inputs (breaking)

The classifier retains ClassifyRequest for its per-request object and RequestClassifierContext for its router-scoped installation context.

  • RequestClassifierContext::workers() returns the WorkerInfo worker selection reads (refactor(router): judge queue capacity on the shared LOAD row #16617), which also carries max_num_batched_tokens. RequestClassifierWorker is removed.
  • The request's input sequence length is isl_tokens() in both plugin APIs, matching SchedulingRequest::isl_tokens and the policy YAML's ISL buckets. WorkerSelectionContext::prompt_tokens() and ClassifyRequest::input_tokens() returned the same value under two names.
  • This breaks out-of-tree classifiers and selection plugins that use the removed worker type or old token accessor names, without aliases: the plugin API is not shipped yet. ThunderAgent, the default scorer, the llm router, tests, and both plugin guides are updated.

Absolute prefill thresholds (deprecated)

The absolute prefill thresholds duplicate the fractional ones, and a worker that does not report max_num_batched_tokens silently gets a 10,000,000-token default under them. Deprecated for removal in v1.7:

  • policy YAML prefill_busy_threshold (logs a warning per class at load);
  • --active-prefill-tokens-threshold / DYN_ACTIVE_PREFILL_TOKENS_THRESHOLD (logs a warning at startup from build_router_config(), so the frontend and any worker advertising the value each warn once; a worker without --router-mode advertises nothing and stays quiet).

Use the _frac forms instead. Docs updated.

The router policy docs now also state that a class with any queue limit set to 0 never queues: it admits while an eligible worker is below the class's busy thresholds, and rejects with 529 when every eligible worker is busy (zero_class_queue_limit_never_queues covers this). That is how a class fails fast when its workers are full, so the DEP's on_full: reject setting is not added: capacity-based rejection stays router-wide (/busy_threshold and the frontend flags), and classes wait.

Validation

After moving the deprecation warning into build_router_config() (review follow-up):

  • test_router_advertisement.py and test_kv_router_args.py: 99 passed, 3 skipped (backends not installed); the two new worker CLI/env cases fail without the fix.
  • mocker/tests/unit/test_config.py, frontend/tests/test_batch_gateway_args.py, frontend/tests/test_batch_gateway_transport.py: 39 passed.
  • pre-commit on the touched files: clean.

After restoring ClassifyRequest:

  • cargo fmt --all --check and git diff --check: clean.
  • cargo test --locked -p dynamo-kv-router --lib --test plugin_api_compat: 1127 unit tests and 1 plugin API compatibility test passed; 3 ignored.
  • cargo test --locked -p dynamo-custom-policy-builtin: 86 tests passed; 2 ignored.
  • cargo check --locked -p dynamo-llm --no-default-features --tests: passed.
  • Targeted docs lint and asset-path checks: passed (5 existing navigation warnings on other pages).

Earlier stack validation (before restoring the type name):

  • cargo fmt --all --check and cargo clippy --workspace --all-targets -- -D warnings: clean.
  • cargo test -p dynamo-kv-router --lib: 1120 passed; plugin_api_compat: passed.
  • cargo test -p dynamo-custom-policy-builtin: passed.
  • cargo test -p dynamo-mocker --lib: 272 passed.
  • cargo test -p dynamo-llm --lib -- kv_router discovery::worker_monitor: 489 passed (including classifier_context_tracks_capacity_and_registered_ranks, which checks max_num_batched_tokens).
  • test_kv_router_args.py: the absolute CLI flag warns; the other flags do not. 2 ais_perf_moe cases fail identically on main (local aisimulate import issue).
  • Docs hooks (codespell, trailing whitespace, Fern asset paths) on the touched pages: clean.

Stack

  1. feat(router): expose worker inputs to request classifiers #16616 feat(router): expose worker inputs to request classifiers
  2. refactor(router): judge queue capacity on the shared LOAD row #16617 refactor(router): judge queue capacity on the shared LOAD row
  3. feat(router): add a decode busy threshold to policy-class queues #16618 feat(router): add a decode busy threshold to policy-class queues
  4. feat(router): enforce busy-reject thresholds in the KV router queue #16619 feat(router): enforce busy-reject thresholds in the KV router queue
  5. refactor(router): unify classifier inputs; deprecate absolute busy thresholds #16620 refactor(router): unify classifier inputs; deprecate absolute busy thresholds (this PR)

@github-actions

github-actions Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

@ishandhanani
ishandhanani added this pull request to stack #16622 October 16, 2026 03:03
@devin-ai-integration

devin-ai-integration Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

✅ Dynamo PR CI passed — run 40457088307 (attempt 1) on 508ed4968c

Gate checks: ✅ backend-status-check · ✅ deploy-status-check · ✅ dynamo-status-check

Posted automatically by Devin for run 40457088307. Updated on every full-CI run of this PR.

@ishandhanani
ishandhanani force-pushed the idhanani/adm-5-on-full branch from dabbcb0 to 54657de Compare October 16, 2026 07:51
@pull-request-size pull-request-size Bot added size/M and removed size/L labels Oct 16, 2026
@ishandhanani ishandhanani changed the title feat(router): let policy classes reject instead of wait when full chore(router): deprecate absolute prefill busy thresholds Oct 16, 2026
@github-actions github-actions Bot added chore and removed feat labels Oct 16, 2026
@ishandhanani
ishandhanani force-pushed the idhanani/adm-5-on-full branch from 54657de to 9577af0 Compare October 16, 2026 09:47

@ishandhanani ishandhanani left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Deprecation only. Warnings are structured, the flag help and every docs page that names the flag are updated, and the "zero queue limit never queues" paragraph matches the existing zero_class_queue_limit_never_queues test. One nit inline.

@ishandhanani
ishandhanani force-pushed the idhanani/adm-5-on-full branch from 9577af0 to 0390cb4 Compare October 19, 2026 01:55
@ishandhanani ishandhanani changed the title chore(router): deprecate absolute prefill busy thresholds refactor(router): rename classifier contexts; deprecate absolute busy thresholds Oct 19, 2026
@pull-request-size pull-request-size Bot added size/L and removed size/M labels Oct 19, 2026
@github-actions github-actions Bot removed the chore label Oct 19, 2026
@ishandhanani
ishandhanani force-pushed the idhanani/adm-5-on-full branch from 033100f to a6fd83f Compare October 23, 2026 05:00
@ishandhanani
ishandhanani force-pushed the idhanani/adm-5-on-full branch 3 times, most recently from dd707fa to 19d6f88 Compare October 23, 2026 09:34
@ishandhanani ishandhanani changed the title refactor(router): rename classifier contexts; deprecate absolute busy thresholds refactor(router): rename the classifier request context; deprecate absolute busy thresholds Oct 23, 2026
@ishandhanani
ishandhanani force-pushed the idhanani/adm-5-on-full branch from 19d6f88 to 5df9abc Compare October 23, 2026 10:56

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

Context naming verified on 5df9abc.

@ishandhanani
ishandhanani force-pushed the idhanani/adm-5-on-full branch from 5df9abc to 4f6018e Compare October 24, 2026 05:13
@ishandhanani
ishandhanani force-pushed the idhanani/adm-5-on-full branch 2 times, most recently from 82f14fc to 311f02f Compare October 25, 2026 05:47
@ishandhanani ishandhanani changed the title refactor(router): rename the classifier request context; deprecate absolute busy thresholds refactor(router): unify classifier inputs; deprecate absolute busy thresholds Oct 26, 2026
The absolute prefill thresholds duplicate the fractional ones and hide
an unreported `max_num_batched_tokens` behind a 10,000,000-token
default. Deprecate policy YAML `prefill_busy_threshold` and
`--active-prefill-tokens-threshold` for removal in v1.7; both log a
warning.

Also document that a policy class with a zero queue limit rejects
instead of waiting when its workers are full, which is how a class
fails fast without a separate setting.

Part of #16543.

Signed-off-by: Ishan Dhanani <ishandhanani@gmail.com>
The classifier's per-request object was `ClassifyRequest`, while worker
selection's per-request object is `WorkerSelectionContext`. Rename it so
the name says what it holds, and give shared request facts one name:

- `ClassifyRequest` -> `RequestClassificationContext`, the per-request
  facts and overrides `classify` receives and returns.
- `RequestClassifierContext`, the router-wide block size and registered
  workers given to a classifier factory, keeps its name;
  `RequestClassifierContext::workers()` now returns the `WorkerInfo`
  worker selection reads, which also carries `max_num_batched_tokens`.
- `RequestClassifierWorker` is removed in favor of `WorkerInfo`.
- The request's input sequence length is `isl_tokens()` in both
  contexts, matching `SchedulingRequest::isl_tokens` and the policy
  YAML's ISL buckets: `WorkerSelectionContext::prompt_tokens()` and
  `RequestClassificationContext::input_tokens()` are renamed.

This breaks out-of-tree classifiers and selection plugins that use the
old names; in-tree users and docs are updated.

Part of #16543.

Signed-off-by: Ishan Dhanani <ishandhanani@gmail.com>
Signed-off-by: Ishan Dhanani <ishandhanani@gmail.com>

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

P3 — Low priority. The new warning is placed in RouterConfigBase.validate_rejection_thresholds(), whose only production caller is frontend validation. However, the same CLI flag and environment variable are also accepted by the worker-side router advertisement parser.

For example, a worker configured with:

--router-mode kv --active-prefill-tokens-threshold 123

passes through parse_worker_router_config() and build_router_config() without invoking that validator. The absolute value is forwarded into the advertised router configuration. The concrete vLLM path calls the parser in args.py and builds the advertisement in main.py; TRT-LLM and SGLang use the same shared functions. The Rust binding constructor also accepts the value without emitting this warning.

Consequence: operators configuring the deprecated setting through worker advertisements miss the promised startup migration notice. This is a gap in the new deprecation behavior, not evidence of incorrect routing or rejection today.

Recommended correction: cover active worker advertisements in the shared configuration path, preserving the frontend's single warning and the current unset behavior. Add coverage for both worker CLI and environment use.

Non-blocking because the absolute setting remains accepted and enforced.

…tisements

The --active-prefill-tokens-threshold deprecation warning lived in
RouterConfigBase.validate_rejection_thresholds(), which only the frontend
runs. A worker advertising a router config with the flag or with
DYN_ACTIVE_PREFILL_TOKENS_THRESHOLD forwarded the value through
parse_worker_router_config() (vLLM, SGLang, TRT-LLM) or
WorkerRouterConfig.from_cli_args() (mocker) without the startup notice.

Emit the warning from build_router_config() instead: every advertisement,
the frontend's included, is built there, so each process warns exactly
once and only when the deprecated value is actually forwarded. A worker
that omits --router-mode advertises nothing and stays quiet, as before.

Cover worker CLI and environment use in test_router_advertisement.py and
pin the frontend's single warning in test_kv_router_args.py.

Part of #16543.

Signed-off-by: Ishan Dhanani <ishandhanani@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation refactor router Relates to routing, KV-aware routing, etc. size/L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants