You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
An Azure DevOps build can stay "Running" after its run completes, because the completed FinishTime is older than the local UtcNow stamped on the last in-progress poll #310
If the server's FinishTime is earlier than the local time stamped on the last in-progress poll, Build never takes the completed status. FinishTime never changes after that, so the build stays wrong until a newer run starts. This happens when:
the local clock is ahead of the Azure DevOps server's clock, even by a second, or
the build finishes while an in-progress response is still in flight, so the poll is processed after FinishTime. BuildSync and RunSync both poll the same run, which makes this window bigger.
Failure scenario
Poll 1 returns the build as InProgress. It is processed at local time T, so Build.LastUpdated = T and LastStatus = Running.
Poll 2 returns Completed/Succeeded with FinishTime = T − 1s.
run.Status becomes Success, but Build.UpdateFromRun ignores it because T − 1s > T is false.
The subagent that reviewed this reproduced it with a scratch MSTest case. The case calls the private UpdateRunFromBuild through reflection with those two build snapshots:
Effect in the UI: the build row keeps showing a progress bar and ETA and stays on the fast (high-priority) poll interval, even though its latest run has finished. Its row in the runs list correctly says Success.
Suggested fix / acceptance criteria
Either of these works:
In Build.UpdateFromRun, for the same run (run.Started == LastStarted), always accept a change from an ongoing status to a finished one, whatever the timestamps say.
Stop using the local clock in the ADO provider. Keep LastUpdated on server times only, or track the latest run's id on Build and always take that run's status.
Add a test that feeds an in-progress snapshot and then a completed snapshot whose FinishTime is earlier than the in-progress poll's local timestamp, and checks that Build.LastStatus ends up Success and IsOngoing is false.
Priority: High. The build row stays "Running" for good once its run has finished: the progress bar and ETA stay up and the build keeps polling on the fast interval until a newer run starts. It only takes clock skew of about a second, or a poll response that arrives late, so it will happen in normal use.
Area / suggested owner: Azure DevOps provider (Providers/AzureDevOps.cs, UpdateRunFromBuild) and the shared Build.UpdateFromRun. The first suggested fix, which always accepts ongoing → finished for the same run, sits in shared code and also protects the GitHub provider, so it is the safer choice.
Notes: The issue already includes a reproduction. The acceptance test it proposes, an in-progress snapshot followed by a completed one with an earlier FinishTime, should come with the fix.
Activity
matt-edmondson commentedon Sep 28, 2026
Triage
Providers/AzureDevOps.cs,UpdateRunFromBuild) and the sharedBuild.UpdateFromRun. The first suggested fix, which always accepts ongoing → finished for the same run, sits in shared code and also protects the GitHub provider, so it is the safer choice.FinishTime, should come with the fix.Generated by Claude Code