fix(playwright): re-trigger when a test-suite pipeline run never leaves the queue - #30875
Conversation
…es the queue The empty-DAG race (Airflow 3.x accepts a trigger before the dag-processor has serialized the freshly deployed DAG) has two shapes: the trigger writes no status at all, OR it produces a transient `queued` run that then vanishes when the empty DAG finishes instantly with no task. waitForNewRunToAppear treated any new run — including that transient `queued` — as "materialized", so it skipped the re-trigger recovery; the run then vanished and the success poll waited out the full timeout (seen in CI as a `queued` status followed by an empty pipelineStatus). Require the run to have actually LEFT the queue (non-`queued` state) before counting it, so the transient `queued` no longer short-circuits the re-trigger — a real run leaves the queue within seconds, the empty-DAG run never does. Follow-up to #30789. Co-Authored-By: Claude <noreply@anthropic.com>
❌ PR checklist incompleteThis PR cannot be merged until the following are addressed on its linked issue:
The fields live on the linked issue in the Shipping project (open the issue → right sidebar → Projects). After you set them, re-run this check (or push a commit) — issue/project changes do not re-trigger it automatically. Maintainers can bypass this check by adding the |
Code Review ✅ ApprovedUpdates the Playwright test helper to check that pipeline runs actually leave the queued state before considering them materialized, preventing 300-second timeouts caused by empty DAG runs. No issues found. OptionsDisplay: compact → Showing less information. Comment with these commands to change the behavior for this request:
Was this helpful? React with 👍 / 👎 | Gitar | Powered by Gitar — free for open source |
There was a problem hiding this comment.
Pull request overview
This PR hardens the Playwright IncidentManager pipeline-trigger helper against an Airflow race where a freshly deployed DAG can briefly report a queued run and then produce no durable pipelineStatus, leading to a full timeout wait.
Changes:
- Tightens the “new run appeared” check to require the latest run to be both new and not in
PipelineState.Queued. - Expands inline documentation to explain the transient-queued / empty-DAG failure mode and why it previously bypassed the re-trigger loop.
✅ Playwright Results — workflow succeededValidated commit ✅ 768 passed · ❌ 0 failed · 🟡 0 flaky · ⏭️ 3 skipped · 🧰 0 lifecycle flaky PerformanceBlocking targets: ✅ met · Optimization targets: 🟡 in progress Shard-job maxima below are not the full workflow wall time; the linked run includes build, fixture, planning, and reporting. 🕒 Full workflow signal wall (to summary) 52m 7s ⏱️ Max setup 2m 53s · max shard execution 18m 0s · max shard-job elapsed before upload 21m 25s · reporting 4s 🌐 200.81 requests/attempt · 2.65 app boots/UI scenario · 11.57% common-shard skew Optimization targets still in progress:
How to debug locally# Download playwright-test-results-<shard> artifact and unzip
npx playwright show-trace path/to/trace.zip # view trace |
Follow-up to #30789 (already merged).
Problem
IncidentManager tests that keep a real pipeline (the main
beforeAlland the re-run tests) intermittently fail in CI withReceived: "queued"→ 300s timeout. Confirmed from a merge-queue run's Airflow diagnostics: the freshly-deployed DAG isn't serialized when OM triggers it (AirflowRESTClient: 404 "DAG … not found"), so the DagRun executes empty (run_duration=0.026s, no task) and writes no status. In the trace this shows as a briefqueuedstatus followed by an emptypipelineStatus.Why the existing recovery missed it
waitForNewRunToAppearre-triggers only when no run appears — but the empty-DAG race produces a transientqueuedrun, and the check counted any run as "materialized", so it skipped the re-trigger. The run then vanished and the success poll waited out the full timeout.Fix
Require the run to have actually left the queue before counting it:
A real run leaves
queuedwithin seconds; the empty-DAG run never does. So the transientqueuedno longer short-circuits the existing re-trigger loop, which fires and triggers again against the now-serialized DAG. If even that fails 3× (pathological saturation) it throws a clear error instead of the silent 300s hang.Scope / validation
🤖 Generated with Claude Code