Repository navigation
Conversation
Under etcd discovery the frontend routes to any endpoint with an admitted model card, whatever the pod's readiness, so a worker held by validation gates must not write its card. With DYN_WORKER_VALIDATION_HOLD=card (the default), register_model_card records engine capacity as before and parks the discovery write in a per-process map. Taint updates and unregister edit that map while the card is held. On release each held card is written in registration order with retry; a final failure fails the publish gate and the worker stays held. hold=health writes the card immediately. Adds DiscoverySpec::with_model_taints so held taint updates follow the same rules as Discovery::update_model_taints. The virtual planner now counts only workers whose model card is published, falling back to endpoint instances when cards cannot be tracked. Signed-off-by: Seb Ringrose <seb@doubleword.ai>
|
Running ultrareview automatically — this PR appears to change concurrency-sensitive code such as locks, queues, or retries, where a missed race may only surface under production load, so a deeper multi-pass review is worth running. I'll post findings when complete. |
There was a problem hiding this comment.
Ultrareview ran automatically — this PR appears to change concurrency-sensitive code such as locks, queues, or retries, where a missed race may only surface under production load, so a deeper multi-pass review is worth running.
All reported issues were addressed across 6 files
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
|
Superseded by the cut-down stack #6 → #7 → #8 → #9 → #10 → #11 (~4,950 → ~2,000 lines): #2 is split into exec gates (#7) and sidecar url gates (#8), the url contract is now 200 = pass, and metrics, the fixed loopback port, the virtual-planner change and the parity harness are dropped. The review threads here stay for reference. 🤖 Generated with Claude Code |
Third of five stacked PRs for the worker validation gates DEP (
ai-dynamo/dynamo#15897). Based on #2. #4 is stacked on this PR so that #5's end-to-end test covers both.Why
Under etcd discovery the frontend routes to endpoint records that have an admitted model card, whatever the pod's readiness. Holding
/healthalone doesn't keep traffic off a held worker, so the card's discovery write has to be held too.What
lib/llm/src/validation_hold.rs:DYN_WORKER_VALIDATION_HOLD=card(the default) and the worker not yet released,register_model_cardparks the card in a per-process map keyed by(connection_id, namespace, component, endpoint, suffix), then returnsOk.publishgate and the worker stays held.update_model_taintsedits the held spec, using the newDiscoverySpec::with_model_taintsso the rules matchDiscovery::update_model_taints(reserved topology prefix and so on).detach_from_endpointdrops the held card and skips the discovery unregister.register_model_cardstill callsrecord_engine_capacity, which sizes the process rather than routing. Without gates, the order is unchanged: register, then record.hold=healthwrites the card immediately._get_actual_worker_countcounts only instances whose model card is published, using the existingFpmEventSubscriber.get_model_cards()snapshot. When cards can't be tracked, it falls back to the endpoint-instance count with a warning.Tests
Discovery-level tests on the in-memory store (
--features integration):hold=healthwrites it immediately;Planner unit tests: workers without a card aren't counted and are counted once the card is published; untracked cards fall back to the endpoint count.
cargo clippy -p dynamo-llm -p dynamo-runtime --all-targets -D warningsis clean, and all 12 virtual-connector tests pass.Known differences
Discovery::register's different-model conflict check runs at write time. Under the hold, a conflicting registration returnsOkand fails at release as apublishgate failure. That's fail-closed, but later than today.register_model_cardaren't held. That covers the vLLM sidecar LoRA path (sidecar mode is rejected at startup) andlib/rl.Stack
/livefrom/health🤖 Generated with Claude Code