Repository navigation
A hung Darling or Lite test shard names its test and still uploads its logs (#5587) - #5591
Merged
Merged
Conversation
…s logs (#5587) The shard test steps get a step-level timeout under the job's 30 minutes, the runner's -longRunning report, and a kept copy of the runner output. The cancelled-refresh wait in RollupBackfillLiveTests is bounded while the chunk lock is held.
erikdarlingdata
marked this pull request as ready for review
October 8, 2026 19:53
…he shards (#5587) -longRunning 300, the runner output teed and uploaded with always(), a step timeout on the Lite step from measured numbers, and the failure upload on failure() || cancelled(). The Darling step keeps no step timeout: its longest measured run is over 70% of the value a timeout would have.
This was referenced Oct 8, 2026
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.
Claude posting for Erik Darling.
Fixes #5587.
Why
Run 37824250187 attempt 1: Darling PG shard 3 ran to the job's 30-minute timeout and was cancelled. Its step list shows what the timeout does. "Run Darling PG tests" was
in_progressand every later step (Warn, Stop PostgreSQL, both uploads) stayedpending. So a JOB timeout skips thealways()steps. No log was kept and no timing was written, because the runner writes the per-test timing only when a chunk ends. A hang did not name its test.What changes
always()steps run. Measured step times: Darling 6 to 11 min (run 37824250187), Lite up to 14 min (runs 37831712873, 37819589143, one full Lite shard). The job stays at 30. Trade-off: the comment above the Lite job (about Lite.Tests on hosted Windows runners grew from ~9½ to ~45 minutes in five days; the unsharded nightly run now exceeds its 90-minute cap #5208) says Lite shards are growing toward the 30-minute cap. 22 leaves 8 minutes over today's slowest. It is one number to raise if the growth continues.-longRunning 300on each chunk's runner call (xUnit v3 4.0.1 has it:-longRunning <seconds>, "implies -diagnostics"). Threshold: the slowest normal Darling test in the timing artifacts is 120 s (the store-upgrade classes), so 300 s is above it and well under the step timeout. Proved it prints with a throwaway test (deleted before the push):[D::Darling.Tests] [Long Running Test] 'Darling.Tests.ThrowawayLongRunning.Sleeps', Elapsed: 00:00:03, repeated while it ran.TestResults/darling-runner-N.log(Lite:lite-runner-N.log) and uploaded as its own artifact (darling-runner-log-N,lite-runner-log-N) withalways(). They are separate from the*-tests-timing-*artifacts because the shadow check and the Lite shard packer read those.failure() || cancelled().RollupBackfillLiveTests(shard 3), see below.Lite has the same gap (job timeout 30, no step timeout, uploads behind the job), so it gets the same changes.
nightly.ymlruns the whole suite in one process under 150-minute job timeouts; it has the same no-name-on-hang shape. That is outside this brief, so it is noted, not changed.Lock-wait ruling (shard 3, attempt 2's
darling-tests-timing-3)Attempt 2's artifact lists 374 test classes for shard 3 (one chunk). I scanned every one of them for
LOCK TABLE,FOR UPDATE,pg_advisory,BeginTransaction,lock_timeout,statement_timeout, then read the classes that hold a lock while waiting on other code:QueryStoreIntervalPartitionsLiveTests(blockers hold ACCESS SHARE / SHARE UPDATE EXCLUSIVE on the interval tables, lines 536-580): every step it calls runs underSET LOCAL lock_timeout = 5s(QueryStoreIntervalPartitions.cs:83LockTimeoutSeconds,:500LockTimeoutSql, used at:715,:892,:942,:1001,:1098,:1256,:1354); Arm's retries are 3 times (30 s apart in the service, 100 ms in the test). The upsert test sets its ownlock_timeout = '2s'(:260). Ends.QueryStoreIntervalPurgeRowCappedTests(row lockFOR UPDATE, line 488): the purge connection carriesstatement_timeout=500. Ends.ProvisioningSerializationTests(advisory locks, lines 192, 279, 521): every wait isWaitAsync(30 s)or has a 60 s argument. Ends.RetiredBaselineAggregateTests(lock_timeout = 1s, line 594). Ends.RollupBackfillLiveTests(line 627 holds ACCESS EXCLUSIVE on a raw chunk): does not provably end. After the test cancels the refresh it did_ = await refresh;while its own lock transaction was still open. The refresh's command timeout isSliceTimeoutSeconds = 60 * 60(RollupBackfill.cs:666), longer than the job. If the cancel never reached the backend, nothing ended that wait. Fixed: the wait isrefresh.WaitAsync(60 s); on the limit the lock is released in the existing finally, the refresh is let finish, and the test fails by name. Honest framing: attempt 1 kept no log, so this is a wait with no end in a shard-3 class that fits the signature, not proof that it was the hang.StatementScrubQueryStatsLiveTests,PlanRegressionDailyTriggerCostRig) hold one connection's own transaction and no second connection waits on it.Can the service wait the same way at start?
Yes, but every wait ends:
PgMigrations.cs:1202-1203, built at:910-918, SQL at:943):SET LOCAL lock_timeout = MigrationCommandTimeoutSeconds - 20= 280 s (:7626has the 300 s command timeout), so a reader holding an open transaction on the interval table makes the rung wait up to 280 s per table, then fail with 55P03 before the client timeout.pg_try_advisory_lockagainstMigrationLockWaitTimeoutSeconds = 5 * 300= 1500 s (:7759, loop at:7888), then it either proceeds (store already current) or throws.QueryStoreIntervalPartitions.cs:500): 5 slock_timeouton each step; Arm retries 3 times 30 s apart (:703-765).So the service can sit for up to 280 s per rung at start behind a long reader, and a test that starts a store behind a long reader looks like a hang for 4 to 5 minutes. I changed no service code.
Nightly
nightly.ymlruns the same two suites in one process each, so it had the same gap. Commit 2c31590 (merged with dev at 118f1a8) gives its two test steps the same report.Run testsfor Lite,Run Darling PG tests) now pass-longRunning 300and tee the runner output toTestResults/lite-runner-nightly.logandTestResults/darling-runner-nightly.log. They still fail when the runner fails, through an explicit$LASTEXITCODEcheck right after the pipe.lite-runner-log-nightlyanddarling-runner-log-nightly. The Darling failure upload now runs onfailure() || cancelled().timeout-minutes: 140.CiShardHangReportTestshas 4 new test cases (12 in all) pinning the nightly steps. Red-plant: with-longRunning 300removed from the nightly Lite step the Lite case failed (Total 12, Failed 1). Restored, it passes.CiShardHangReportTests,*Census*,*Ratchet*,*DocCommentHygiene*(590 tests, 0 failed, 1 skipped) andStage=Guard(1432 tests, 0 failed). Build 0 warnings.nightly.ymlandbuild.ymlparse as YAML. Never dispatched the nightly workflow, so no real runner has run these steps yet.Test plan
CiShardHangReportTests(new, 8 tests): step timeout present and under 25 min,-longRunningbetween 150 and 600 s, Tee to the runner log, uploads run onalways(), failure upload onfailure() || cancelled(), runner logs not inside the timing artifacts, and the Rollup wait pin. Red-planted once: with-longRunning, the step timeouts andcancelled()removed from the fixture copy, 5 of 7 failed; with the oldRollupBackfillLiveTests.cs, the pin failed.CiShardCommandLineBudgetTests,RollupBackfillLiveTests(live, on a throwaway rig at port 55551, 0 skipped): pass.*Census*,*Ratchet*,*DocCommentHygiene*plus the two classes above: 594 total, 0 failed, 10 skipped (no rig).-trait Stage=Guard: 1420 total, 0 failed.build.ymlparses as YAML.[Long Running Test]line and the runner-log artifact; watch one run.Head: see the PR.