Repository navigation
Don't crash retried lazy-load workers when the queue is almost empty - #440
Merged
Merged
Conversation
When a retried worker finds no more tests left in the queue than are running, `minitest-queue run` skips loading tests and populating the queue, expecting the queue to be empty by the time the application boots. Without lazy loading, minitest runs from minitest/autorun's at_exit hook, which loading the test files registers. No test files load, so the worker exits 0. In lazy-load mode the runner calls `Minitest.run` itself, and only skips it when the queue is exhausted, which it isn't while other workers still hold tests. The worker then polls a queue that can't resolve entries: the first test it reserves comes back as an `UnresolvedEntry`, and `example.run` raises NoMethodError. The worker records a worker error and exits 42, so `report` prints "Worker N crashed" and exits 42 even when every test passed. In lazy-load mode, also exit 0 without running tests when the queue wasn't prepared.
tekmaven
marked this pull request as ready for review
October 14, 2026 16:51
kylem-work
approved these changes
Oct 14, 2026
kylem-work
left a comment
There was a problem hiding this comment.
LGTM 👍 We shouldn't be trying to intake tests if the queue setup hasn't even run.
This branch was successfully deployed
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.
Why
When a worker is retried (
BUILDKITE_RETRY_COUNT> 0, or a Semaphore rerun) and finds no more tests left in the queue than are running,minitest-queue runprints "Queue almost empty, exiting early..." and skips loading tests and populating the queue (#257, runner.rb). That step is also where the queue gets its entry resolver (queue_population_strategy.rb). Without lazy loading, minitest runs fromminitest/autorun's at_exit hook, which loading the test files registers. No test files load, so the worker exits 0.In lazy-load mode (
--lazy-load,--preresolved-testsorCI_QUEUE_LAZY_LOAD), the runner callsMinitest.runitself and only skips it when the queue is exhausted (#375, #386, runner.rb). The queue isn't exhausted while other workers still hold tests, so the worker starts polling. The first test it reserves comes back fromresolve_entryas anUnresolvedEntry(worker.rb), andexample.runraises (queue.rb):The worker records a worker error and exits 42 (queue.rb).
reportthen prints "Worker N crashed" and exits 42 (build_status_reporter.rb), even when every test passed. The test the worker reserved stays inrunninguntil another worker reclaims it as lost.What
In lazy-load mode,
runnow exits 0 without running tests when it didn't prepare the queue, as it already did when the queue was exhausted. A retried worker that finds the queue almost empty now exits the same way it does without lazy loading.Behavior
Scenario: 1 test is left in the queue and another worker holds 2. A
--lazy-loadworker runs withBUILDKITE_RETRY_COUNT=1.Before (exit status 42):
After (exit status 0):
Other cases:
rspec-queueand the Python client don't have this early exit.Tests
test_lazy_load_retry_exits_without_reserving_tests_when_queue_is_almost_emptyinruby/test/integration/minitest_redis_test.rb. A worker streams 3 tests and reserves 2, leaving 1 in the queue. A--lazy-loadworker then runs withBUILDKITE_RETRY_COUNT=1andBUILDKITE_RETRY_TYPE=automatic. It exits 0, prints the two lines above, leaves the last test in the queue, and records no worker error. It fails onmain(exit status 42) and passes with this change.Results locally on Redis 8.6.3 and Ruby 4.0.7: