DEVOPS-213: How to identify, quarantine, and graduate flaky CI jobs without weakening required protections.
A flaky check is a CI job that passes and fails non-deterministically on the same code. Flaky checks erode trust in CI and cause unnecessary re-runs. This process provides a structured way to handle them without disabling required protections.
All quarantine state lives in .github/flaky-quarantine.json. This file is committed to the repository so the quarantine list is visible to all maintainers and tracked in git history.
{
"quarantined": [
{
"job": "E2E Tests",
"reason": "Playwright timing issue on slow runners — tracked in #42",
"quarantined_at": "2025-01-15T10:00:00Z",
"review_by": "2025-01-29"
}
],
"graduated": []
}# Detect flakiness by re-running a job 5 times
TEST_CMD="npm run test:run -w web" \
./scripts/quarantine-flaky-check.sh detect "Web Unit Tests" 5
# Manually quarantine a known-flaky job
./scripts/quarantine-flaky-check.sh add "E2E Tests" "Playwright timing issue — see #42"
# List all quarantined jobs
./scripts/quarantine-flaky-check.sh list
# Print CI-friendly report (exits 1 if any quarantine is overdue)
./scripts/quarantine-flaky-check.sh report
# Graduate a fixed job out of quarantine
./scripts/quarantine-flaky-check.sh remove "E2E Tests"The flaky-quarantine.yml workflow runs every Monday at 06:00 UTC and:
- Runs
reportto list all quarantined jobs and flag overdue ones. - Uploads the quarantine state as a workflow artifact (retained 90 days).
- Posts a
::warning::annotation in the Actions UI if any quarantine is overdue.
You can also trigger it manually from the Actions tab to run flaky detection on a specific job.
- Quarantine does not disable the check. The job still runs in CI. Failures are annotated but do not block merge while the job is under investigation.
- Every quarantine has a review date (14 days from quarantine by default). The weekly workflow flags overdue entries.
- Quarantines must be resolved. Either fix the root cause and graduate the job, or open a tracking issue and extend the review date with a comment explaining why.
- Required checks remain required. Quarantine is a tracking mechanism, not a bypass. If a required check is flaky, the fix is to stabilize it — not to remove it from the required list.
- Identify the root cause (timing, test isolation, external dependency, resource contention).
- Apply the fix in a PR.
- Run the detection script to confirm stability:
TEST_CMD="..." ./scripts/quarantine-flaky-check.sh detect "<job>" 10 - Graduate the job:
./scripts/quarantine-flaky-check.sh remove "<job>" - Commit the updated
.github/flaky-quarantine.json.
| Cause | Fix |
|---|---|
| Timing / async race | Add explicit waits; avoid setTimeout in tests |
| Shared test state | Isolate test data; use beforeEach cleanup |
| External service dependency | Mock the service in unit/integration tests |
| Port conflicts | Use dynamic port allocation |
| Resource exhaustion on CI runner | Reduce parallelism; add retry logic |