Repository navigation
feat(router): expose worker inputs to request classifiers - #16616
Conversation
✅ Dynamo PR CI passed — run 40457088283 (attempt 1) on
|
ishandhanani
left a comment
There was a problem hiding this comment.
Reviewed with the whole stack (#16616 to #16620) checked out at the tip. Locally: cargo test -p dynamo-kv-router --features standalone-indexer --lib 1164 passed, clippy -D warnings clean on kv-router, mocker, and llm.
The seam is sound: one row builder for both consumers, NONE builds nothing, snapshot timing is documented. Two inline notes, on the classify path's per-request allocation and on the shared builder's inlining.
3122234 to
c084701
Compare
jthomson04
left a comment
There was a problem hiding this comment.
Two notes on the classifier rows: memory held per pending classification, and work done under the worker-config read guard.
c084701 to
7035301
Compare
af73e78 to
91fc895
Compare
jthomson04
left a comment
There was a problem hiding this comment.
One perf note on retries in the classify path.
91fc895 to
3918a95
Compare
jthomson04
left a comment
There was a problem hiding this comment.
Retry-path fix verified on 3918a95.
8fa11cf to
5bfcfef
Compare
Admission plugins can now declare `WorkerInputs` with `RequestClassifier::required_worker_inputs` and receive per-worker rows as the `workers` argument of `classify`. Rows come from the row builder worker selection uses, so CACHE, LOAD, and PREFERRED_TAINT mean the same thing in both seams. The default `WorkerInputs::NONE` builds nothing. The rows are a snapshot lent for the synchronous `classify` call only; the host drops them before awaiting the classification future, so a deferred classification does not hold memory per worker rank. Worker selection still takes its own snapshot when it picks a worker. A retry whose lifecycle already carries classification overrides returns from `classify_with` before the plugin runs, so `classify_request` asks the runtime first and skips the load projection and the row build for it. Signed-off-by: Ishan Dhanani <ishandhanani@gmail.com>
5bfcfef to
48b6b96
Compare
Signed-off-by: Ishan Dhanani <ishandhanani@gmail.com> # Conflicts: # lib/kv-router/src/scheduling/selector/mod.rs
Part of #14823. Replaces #16502, moved to an upstream branch so the admission capacity stack for #16543 can build on it (PR 1 of 5).
Summary
Request classifiers (the admission-control seam) now read the same per-worker
WorkerInputsthat worker-selection filters, scorers, and pickers use. Before this change a classifier only saw discovery data (block size and total KV blocks per rank), so admission plugins had to rebuild load from lifecycle events. This covers the #14823 items "let classifiers declare which data they need, likeWorkerInputs, and skip optional work they do not need" and "prepare inputs in shared host code".RequestClassifier::required_worker_inputs()declares the groups. The default isWorkerInputs::NONE, so existing classifiers, including ThunderAgent, build nothing and pay nothing.classifyreceives the rows asworkers: WorkerCandidates<'_>, a view restricted to the declared groups (empty forNONE). The host builds them for each call, lends them for the synchronous call only, and drops them before awaiting the classification future, so a deferred classification holds no per-rank memory. The borrow keeps the view from escaping into the'staticfuture.RequestClassifier::classifygains theworkersargument, matching how filters, scorers, and pickers receive their rows. A classifier that declares no inputs adds_workers: WorkerCandidates<'_>and ignores it. ThunderAgent and the in-tree tests and docs are updated.MaterializedSelectionInputintoworker_input_row, which selection and classification both call, soCACHE,LOAD, andPREFERRED_TAINTmean the same thing in both seams.LOADis declared, the classify path projects worker load with the sameproject_worker_loads_intothe scheduler actor uses, then frees that projection after building the rows, so a queued request does not keep one map entry per worker.Each seam reads data when it decides, so the two snapshots are separate on purpose. Classifier rows are advisory: they cover eligible ranks including overloaded workers, and selection can pick a different worker.
Rows are a snapshot taken for the
classifycall. A classifier that defers copies what it needs into its future and must not treat that copy as current load later. A live view, for classifiers that hold requests and decide at release time such as ThunderAgent, will follow in a separate PR. ThunderAgent keeps its event-based accounting for now.The admission-control guide documents the new inputs, their snapshot timing, and an example.
Validation
classifier_reads_declared_worker_inputs: a classifier declaringCACHE | LOADsees both eligible ranks with device overlap,is_available, and active requests. It fails as expected when the classify-time load projection is disabled. Existing classifier tests assertworkersis empty forWorkerInputs::NONE.classify_requestasks the runtime once (cached_overrides) and passes no inputs, sinceclassify_withreturns the cached overrides before the plugin runs. Testcached_overrides_follow_the_lifecycle.cargo test -p dynamo-kv-router --features standalone-indexer --lib: 1169 passed.cargo test -p dynamo-custom-policy-builtin: all passed, including ThunderAgent.plugin_api_compat: passed.cargo clippywith-D warnings: clean ondynamo-kv-routeranddynamo-custom-policy-builtin(all targets) and on the workspace.pre-commit: passed.custom-admission-control.mdcompiles against the public API. It counts only observed loads and requires at least one, per CodeRabbit's review of feat(router): expose worker inputs to request classifiers #16502.main; the code moved, it did not change): in release buildscollect_policy_candidatesis the same size (2720 B) and its two inlined closures changed by +62 B and -100 B. An interleaved A/B ofworker_selectionbenches at 10k workers on a shared, busy host was within noise (run-to-run spread 20-40%, overlapping ranges).Summary by CodeRabbit
New Features
Documentation
Stack