Skip to content

Fix poller race condition that missed long-running builds - #18

Merged
jaredpar merged 1 commit into
mainfrom
jaredpar-fix-poller-missed-builds
Jun 22, 2026
Merged

Fix poller race condition that missed long-running builds#18
jaredpar merged 1 commit into
mainfrom
jaredpar-fix-poller-missed-builds

Conversation

@jaredpar

Copy link
Copy Markdown
Owner

Motivation

Build 1475700 (roslyn-CI, a 75-minute PR build) completed but never appeared in Tiger. The root cause is a race condition in BuildPoller: the AzDO API returned builds of any status, but only completed ones were ingested. The watermark (highest ingested build ID) would advance past long-running builds via other completed builds with higher IDs, permanently skipping them once they finished.

Approach

Two changes work together to fix this:

  1. statusFilter=completed on AzDO API calls -- GetBuildsForRepositoryAsync and GetRecentBuildsAsync now accept an optional statusFilter parameter. The poller passes "completed" so only terminal builds (succeeded, failed, canceled) are returned, never in-progress ones.

  2. Replace watermark with DB existence check -- Instead of tracking a high-water-mark build ID, FilterNewBuilds simply checks whether each build already exists in the database. Builds already ingested are skipped; new builds are always picked up regardless of ID ordering. This eliminates the class of bugs where ID ordering doesn't match completion ordering.

The InsertBuild path is unchanged -- INSERT OR REPLACE for the build row and INSERT OR IGNORE for ingestion tasks remain idempotent.

What's not included

Re-run detection (same build ID, new results after "Retry failed jobs") is intentionally deferred. It needs a dedicated design around storing build version info on ingestion tasks so stale results can be filtered at processing time.

Tests

  • FilterNewBuilds_NewBuildsAreIncluded -- new builds pass through
  • FilterNewBuilds_AlreadyIngestedBuildsAreSkipped -- duplicate builds are filtered
  • FilterNewBuilds_LongRunningBuildNotMissed -- the exact scenario from the bug: build 150 completes after builds 100 and 200 are already ingested, and is correctly picked up

The BuildPoller used a watermark (highest ingested build ID) to skip
already-seen builds. The AzDO API returned builds of any status, but
only completed ones were ingested. When a long-running build was still
in-progress, the watermark would advance past it via other completed
builds with higher IDs. Once the long-running build finally completed,
it was permanently skipped.

Fix:
- Add statusFilter=completed to GetBuildsForRepositoryAsync and
  GetRecentBuildsAsync so only terminal builds are returned
- Replace watermark-based dedup with a simple DB existence check
  (FilterNewBuilds) -- builds already in the DB are skipped, new
  builds are always picked up regardless of ID ordering

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jaredpar
jaredpar merged commit e3cb2b1 into main Jun 22, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant