Repository navigation
fix(cli): read the spawner's sessions field in the Docker sandbox drain - #5429
Merged
Merged
Conversation
The Docker deploy's sandbox drain read an `inFlight` field from
GET /v1/drain-status, but the spawner has answered
{draining, sessions, sessionIds} since the one-shot lane was retired.
Every status read came back "unknown", so each Docker deploy waited the
full 300 s drain budget before recreating the spawner.
The drain-status schema now lives once in deployment/runtime-spawner.ts
and both the managed runtime and the Docker drain parse with it. A
failed status call is still "unknown" and keeps polling. An answer that
breaks the contract warns once and is also treated as "unknown": a
drifted answer proves nothing about the sessions still held, so it never
reads as drained. The fake runtime answers the spawner's real shape.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Defect
Every Docker
tale deploythat recreates the sandbox spawner waited the full 300 s drain budget, even when the spawner was idle.Root cause
tools/cli/src/lib/actions/drain-sandbox.tsread aninFlightfield from the spawner'sGET /v1/drain-status. The spawner stopped sending that field in #2301 (2026-07-02). Since then it answers{draining, sessions, sessionIds}(services/sandbox/src/control-routes.ts). Every read parsed as "unknown", so the poll always ran to its deadline. The fake runtime still answered the old{"inFlight":0}, which is why no test caught it. The Incus path (deployment/runtime-spawner.ts) already read the right shape.Fix
spawnerDrainStatusSchema/parseSpawnerDrainStatusinruntime-spawner.ts. The parse also checks that the count matches the unique ids. The managed (Incus) runtime and the Docker drain both use it.sessions === 0.The
inFlightreaders that remain are the backend's/api/control/drain-status(drain-backend.ts), which really does sendinFlight, and the Incus malformed-status fixtures, which use it on purpose. Neither is touched.Regression test
drain-sandbox.test.tsnow uses the spawner's real answer. One new test checks that an idle spawner returns after a single status read with no warning. Four more cover the broken-contract answers: each warns once and then waits as "unknown". To prove the regression, I put origin/main'sdrain-sandbox.tsback under the new tests: 7 of 16 fail. With the fix, 16 of 16 pass.What was run (ops-lab3-ci, tools/cli, after
bun run generate)bun teston drain-sandbox, runtime-spawner, runtime-configuration and runtime-incus-apply: 68 pass, 0 fail.tsc --noEmit: clean.oxlint: 0 warnings, 0 errors.oxfmt --check: clean.bun test: 4602 pass, 4 fail. Clean origin/main fails the same 4 (4597 pass): 'cached site plans preserve Compose overrides…', 'Checks execution optimizations > platform Unit…', and two 'real non-cone scope and readiness checkouts' tests.