Skip to content

test: the start lock promises mutual exclusion, not one winner ever - #284

Merged
piwi3910 merged 1 commit into
mainfrom
fix/start-lock-race-test
Sep 9, 2026
Merged

piwi3910 merged 1 commit into
mainfrom
fix/start-lock-race-test

Conversation

@piwi3910

@piwi3910 piwi3910 commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

The Windows job on the v3.6.0 tag failed with 2 callers won the start race, want exactly 1. The lock is right; the test was wrong.

Every goroutine released after holding 5ms, inside the goroutine. A caller scheduled after that release then acquires the lock legitimately — so "two callers won" was two callers winning in sequence, which is correct behaviour counted as a failure.

Windows found it because its scheduling spreads ten goroutines over more than the five milliseconds the winner held. macOS and Linux happened to fit inside that window, which is why this passed on #272 and #282 and only failed on the tag.

The fix

Every winner holds until all ten have tried; the count is taken then. That is the property the lock actually promises — one holder at a time — and it still fails if O_EXCL is dropped. The lock is also asserted reusable after release, so holding to the end cannot hide a broken release.

No production code changed. 30 consecutive runs green, plus -race.

The Windows job on the v3.6.0 tag failed with "2 callers won the start
race, want exactly 1", and the lock was right — the test was wrong.

Every goroutine released after holding for 5ms, inside the goroutine. A
caller scheduled after that release then acquires the lock legitimately,
so "two callers won" was two callers winning in SEQUENCE. Windows found it
because its scheduling spreads ten goroutines over more than five
milliseconds; macOS and Linux happened to fit inside the window, which is
why this passed on two PRs and failed on the tag.

What the lock promises is that one caller holds at a time, not that only
one ever succeeds across time. Every winner now holds until all ten have
tried, and the count is taken then — which is the promise, and which still
fails if O_EXCL is dropped. The lock is also asserted reusable after
release, since holding to the end would otherwise hide a release that does
not work.

No production code changed.

docs: none — test-only change
Copilot AI lite review requested due to automatic review settings September 9, 2026 19:58

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The change is isolated to tests and correctly aligns the assertion with the lock’s mutual-exclusion semantics while retaining a strong regression trigger (O_EXCL removal).

Pull request overview

This PR fixes a flaky Windows-only failure by correcting TestStartLockUnderRace to assert the lock’s actual contract: mutual exclusion (only one holder at a time), rather than “exactly one winner ever” across time/scheduling.

Changes:

  • Updates the race test to keep the winning lock held until all goroutines have attempted acquisition, preventing legitimate sequential acquisitions from being counted as failures.
  • Adds a post-release assertion that the lock is reusable after being released.
  • Expands the test’s comment and “proved by” note to document the prior failure mode and the intended property.
File summaries
File Description
internal/api/start_test.go Reworks TestStartLockUnderRace to correctly validate start-lock mutual exclusion and reusability under concurrent attempts.
Review details
  • Files reviewed: 1/1 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@piwi3910
piwi3910 merged commit fc5ad6d into main Sep 9, 2026
12 checks passed
@piwi3910
piwi3910 deleted the fix/start-lock-race-test branch September 9, 2026 20:24
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.

2 participants