Skip to content

fix: claim the pending build marker atomically - #29

Merged
Thejus-Paul merged 2 commits into
mainfrom
fix/single-flight-build-claim
Sep 14, 2026
Merged

Thejus-Paul merged 2 commits into
mainfrom
fix/single-flight-build-claim

Conversation

@Thejus-Paul

@Thejus-Paul Thejus-Paul commented Sep 14, 2026 •

Copy link
Copy Markdown
Member

Fixes #30.

Three builds for the same gem were dispatched within three seconds of each other. Two of them compiled fine and then failed on the final upload with a 403, while the third succeeded. The two that failed had produced perfectly good binaries and threw them away, each having occupied a runner and consumed one of the month's build allowance.

When several people request the same uncached gem at once, the service is meant to start one build and let the rest wait for it. The check deciding whether a build was already running read a marker that the other requests had not yet written, so all three concluded nothing was running. Each then stamped its own one-time upload token over the previous one, and only the last token was still valid by the time the builds finished.

That decision is now made in a single step only one request can win, so simultaneous requests for the same gem start one build. Requests that lose the race stop there instead of dispatching a build that gets rejected at the end. A second commit adds the automation that runs the test suites, which until now nothing did.

Concurrent cache misses for one key each read _pending/<key>, found it
absent, and wrote their own nonce into it. Only the last write survived,
so every build but one was dispatched carrying a nonce the worker no
longer recognised, and failed its push with a 403 after occupying a
runner and a monthly build slot.

The marker is now claimed with a conditional put, so exactly one caller
dispatches. An expired marker is replaced by etag rather than deleted
and rewritten, which would let one caller wipe a claim another had just
made.
@Thejus-Paul Thejus-Paul self-assigned this Sep 14, 2026
Nothing ran either suite automatically. The only workflow in the repo is
the gem builder, which is workflow_dispatch only, so a regression could
land on main without anything noticing.

Ruby runs across the versions the README claims support for. Rubocop is
deliberately left out for now: the tree has 25 outstanding offences and
wiring it up would make CI red on arrival.
@Thejus-Paul
Thejus-Paul marked this pull request as ready for review September 14, 2026 14:14
@Thejus-Paul
Thejus-Paul merged commit e2bc762 into main Sep 14, 2026
5 checks passed
@Thejus-Paul
Thejus-Paul deleted the fix/single-flight-build-claim branch September 14, 2026 14:14
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.

Concurrent cache misses for one gem dispatch duplicate builds that all but one fail

1 participant