Repository navigation
air: Report each --watch STATUS transition once and never after the run ends - #7621
Draft
artemy-kolesnikov wants to merge 2 commits into
Draft
artemy-kolesnikov wants to merge 2 commits into
artemy-kolesnikov wants to merge 2 commits into
Conversation
…un ends When the Bricklens stream of `air run --watch -o json` hands off to the MLflow fallback (an empty terminal stream, FEATURE_DISABLED, or MLflow logs found while active), the fallback restarted transition tracking from the status resolved before streaming. A run cancelled while PENDING therefore emitted PENDING, CANCELED, PENDING, CANCELED; a FEATURE_DISABLED handoff emitted PENDING twice; an active handoff regressed RUNNING to PENDING. - The STATUS sink in `air run --watch -o json` drops repeats and anything after a terminal state, and reports the last state it actually emitted as previous_status. - fetchLogs passes the status Bricklens last observed into the MLflow fallback, which reports it instead of the stale pre-stream status. The fallback still follows on the pre-stream status, so a followed run keeps the active MLflow stream (lenient first pass, grace wait, re-read, uncapped output, partial-line hold-back) rather than the capped completed tail. Co-authored-by: Isaac <no-reply@databricks.com>
Collaborator
✅ Integration test reportCommit: 8783969
Top 3 slowest tests (at least 2 minutes):
|
Co-authored-by: Isaac <no-reply@databricks.com>
This branch has not been deployed
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.
Title: air: Report each --watch STATUS transition once and never after the run ends
Changes
air run --watch -o jsonemits aSTATUSevent on each lifecycle transition. When the Bricklens stream hands off to the MLflow fallback, the fallback started its own transition tracking from the status resolved before streaming. A run cancelled while PENDING with no logs therefore emitted (current<-previous):With this change all three emit each transition once, in order, ending at the terminal state:
The change has two parts. The tests show that each one is needed.
newStatusTransitionReporter,logstream_support.go; wired atrun.gowhereonStatusChangeis set). It drops a repeat of the last reported state and anything after a terminal state, and it reports the last state it actually emitted asprevious_status. Non-terminal order is not otherwise policed.fetchLogs→mlflowLogFallbackReporting→followMLflowLogs).streamBricklensLogsWithLatestStatusreturns the status the Bricklens loop last observed. The MLflow stream reports that status until its first refresh, so it never surfaces the stale pre-stream one. The fallback's control flow is unchanged: it still follows on the pre-stream status. A run that was being followed keeps the active MLflow stream, with its lenient first pass, 3 s grace wait, re-read, uncapped output, per-chunk offsets and partial-line hold-back. It does not switch to the 10,000-line completed-tail path. The two-pass grace and the three empty terminal Bricklens polls are untouched.The existing
streamBricklensLogs,mlflowLogFallbackandstreamMLflowLogssignatures are kept as thin wrappers, so their callers and tests don't change. Text mode is unaffected; it has no STATUS sink.Why
A report against a workspace:
air run --watchtakes about 60 s to notice a cancel made from another terminal. Investigating it turned up this event-ordering bug. A JSON consumer that treats eachSTATUSas a state machine saw the run go back to PENDING after CANCELED.This patch does not change how quickly a cancel is noticed. A live smoke against a workspace (below) showed the Jobs run state itself staying
RUNNINGfor 67-87 s after a successfulair cancel. Both the patched and the unpatched watch reported CANCELED within about 0.5 s of Jobs flipping, and exited about 2.4 s later. A proposal for the client-side blocking-call case is under "Follow-up design" and isn't implemented here.Tests
cmd/air/run_watch_status_test.go(new). These are full-commandair run --watch -o jsontests againstlibs/testserver. They assert the exactSUBMITTED/STATUSsequence and the closing envelope:TestRunWatchJSONStatusAfterEmptyBricklensHandoff: the run flips PENDING → CANCELED during the first empty workflow-logs poll, and the MLflow IDs appear only on the second fallback lookup. It assertsSUBMITTED, PENDING<-, CANCELED<-PENDING, at least 2 get-output calls (the grace re-read still happens), and all 10,002 lines across two chunks printed (uncapped). The envelope is CANCELED.TestRunWatchJSONStatusAfterFeatureDisabledHandoff: a 403 FEATURE_DISABLED handoff. It assertsSUBMITTED, PENDING<-, CANCELED<-PENDINGand a CANCELED envelope.TestRunWatchJSONStatusAfterActiveMLflowProbeHandoff: MLflow logs are found while RUNNING. It assertsSUBMITTED, PENDING<-, RUNNING<-PENDING, SUCCESS<-RUNNING.TestStatusTransitionReporterDropsRepeatsAndPostTerminalStates: a unit test of the guard.c7d55d3a6, the first two tests fail with the sequences shown above. With only the guard (status not carried), the third test fails with... RUNNING<-PENDING, PENDING<-RUNNING, SUCCESS<-PENDING.go test ./cmd/air/... -count=1(194 s).go test -raceon the touched watch, logstream and MLflow tests passes. A full-race ./cmd/airrun fails only inTestIndexStrategy*(list_index_test.go:43). That failure reproduces on unpatchedc7d55d3a6and isn't touched here.gofmt,golangci-lint run ./cmd/air/...(0 issues) andtools/validate_nextchanges.pypass.Live smoke (against a workspace, 2026-11-13)
One 1×GPU_1xA10
sleep 120workload (max_retries: 0) per build, run withair run --watch -o jsonand cancelled from a second process about 5 s after the first STATUS event:| build | STATUS events | cancel accepted → Jobs TERMINATED/CANCELED | → watch CANCELED event | → exit | exit code |
|---|---|---|---|---|---|---|
| patched |
RUNNING<-,CANCELED<-RUNNING| 87.5 s | +0.2 s | +2.4 s | 1 || unpatched |
RUNNING<-,CANCELED<-RUNNING| 68.2 s | -0.5 s (watch saw it first) | +2.4 s | 1 |Both runs reached RUNNING immediately and printed 7 environment-setup log lines, so this exercised the normal path, not an MLflow handoff. An independent observer polling
jobs get-runandair get -o jsononce per second saw JobsRUNNINGandair getPENDINGfor the whole interval. Both changed to CANCELED at the same moment.Follow-up design (not implemented): an independent status monitor
Under a stalled log request, the watch can't see a cancel. Bricklens is polled serially:
runs/getis refreshed only between iterations, after each workflow-logs GET and its SDK retries. A held request therefore delays noticing the cancel by up to the SDK's 60 s inactivity timeout (a ~68 s delay reproduced locally with an injected stall).Proposal:
We considered and rejected a fixed 8 s deadline on the whole terminal drain, plus an 8 s "status unknown → exit nonzero" rule:
logstream.goandlogmlflow.go.The smoke above suggests the delay users see may be dominated by Jobs cancel propagation, not by the client. It's worth confirming with request traces before investing in the monitor.
This pull request and its description were written by Isaac.