Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions .github/workflows/reusable-ci-minimal.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# file: .github/workflows/reusable-ci-minimal.yml
# version: 1.0.0
# version: 1.1.0
# guid: c9d8e7f6-a5b4-3c2d-1e0f-9a8b7c6d5e4f
# last-edited: 2026-05-01
# last-edited: 2026-08-12

# Fast parallel CI for PRs and pushes. Runs short tests only.
# Uses manual actions/cache — NOT setup-go's built-in cache, which is unreliable.
Expand Down Expand Up @@ -99,7 +99,20 @@ jobs:
go-test-short:
name: Go Tests (short, race)
runs-on: ubuntu-latest
timeout-minutes: 20
# 35, not 20. The test step below runs `go test` with `-timeout 30m`, so a
# job cap of 20 killed the runner TEN MINUTES BEFORE Go's own timeout could
# fire — and Go's timeout is the only thing that prints a goroutine dump
# naming the stuck test. Every such run produced `conclusion=cancelled`
# with no evidence whatsoever, and `cancelled` reads as a test failure on
# the PR even though nothing failed. Observed repeatedly in
# falkcorp/audiobook-organizer (#2311, #2315, #2319 — the last cancelled at
# exactly 20m16s).
#
# INVARIANT: this cap must stay strictly greater than the longest -timeout
# passed to any `go test` invocation in this job, plus setup time. If you
# raise the test timeout, raise this too — otherwise you silently make
# every slow run undiagnosable again.
timeout-minutes: 35
env:
GOEXPERIMENT: ${{ inputs.go-experiment }}
steps:
Expand Down
24 changes: 24 additions & 0 deletions changelog.d/20260812-go-tests-cap-above-test-timeout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
### Fixed

#### `Go Tests (short, race)` can now reach its own `go test` timeout

The job capped at 20 minutes while its test step ran `go test -short -race
-timeout 30m ./...`. The runner therefore killed the job ten minutes before
Go's own timeout could fire — and Go's `-timeout` is the only thing that prints
a goroutine dump naming the stuck test. Every slow run produced
`conclusion=cancelled` with no diagnostic output at all, and `cancelled`
renders on a PR as a test failure even though nothing failed.

Observed repeatedly in `falkcorp/audiobook-organizer` (#2311, #2315, #2319 —
the last cancelled at exactly 20m16s on a docs-only PR, with every other job in
the run green). Consuming repos could not work around it: this workflow exposes
no timeout input, so the cap is only settable here.

The cap is now 35, and the invariant is stated in a comment beside it: **the
job cap must stay strictly greater than the longest `-timeout` passed to any
`go test` invocation in the job, plus setup.** Raising the test timeout without
raising the cap silently makes every slow run undiagnosable again.

Raising a job cap cannot turn a passing run into a failing one — it only lets a
genuinely slow or hung run survive long enough to emit the dump that identifies
the culprit. Suites finishing well under 20 minutes are unaffected.
Loading