Fix the flaky thread count assertion in the listen keepalive test - #542
Merged
koic merged 1 commit intoSep 4, 2026
Merged
Conversation
## Motivation and Context
"listen keepalive is not started when the interval is nil" fails intermittently on CI. The most recent run failed
on Ruby 3.2 alone while 3.1 and head passed, and a re-run of the same commit went green.
The assertion samples a process-wide count:
```ruby
before = Thread.list.size
open_listen_stream(id: "listen-1", notifications: { toolsListChanged: true })
assert_equal before, Thread.list.size, "a nil interval must not spawn a keepalive thread"
```
`Thread.list` covers the whole process, so the count moves for reasons this test has no interest in.
The observed failure reported 54 against 51: three threads had *gone away* between the samples, not appeared.
This file starts threads in sixteen places, and the SSE stream and reaper threads they leave behind finish whenever
they finish, so whether the count holds still depends on the test order and on the scheduler rather than on
the behavior under test.
The test itself is asking the right question. `setup` builds its transport with `listen_keepalive_interval: nil`
precisely so opening a listen stream spawns no timer, and the point is to hold that guarantee. Only the measurement is wrong,
so this compares the set of threads instead: a thread that disappears no longer registers, and a thread that appears still does.
Minitest runs these tests serially and `open_listen_stream` drives the SSE body inline rather than on a thread,
so a keepalive timer is the only thread that can appear across the two samples.
No library code changes.
## How Has This Been Tested?
The rewritten assertion was checked for sensitivity before being kept: a temporary probe pointed `open_listen_stream` at
a transport built with `listen_keepalive_interval: 15` and asserted the set difference was *not* empty. It passed,
confirming the assertion still catches a spawned keepalive thread rather than merely never failing. The probe was
removed afterwards.
The failure did not reproduce locally beforehand, across six seeds of the file on its own and six full-suite runs,
which matches a timing-sensitive flake that needs a slower machine.
## Breaking Changes
None.
atesgoral
approved these changes
Sep 4, 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.
Motivation and Context
"listen keepalive is not started when the interval is nil" fails intermittently on CI. The most recent run failed on Ruby 3.2 alone while 3.1 and head passed, and a re-run of the same commit went green.
The assertion samples a process-wide count:
Thread.listcovers the whole process, so the count moves for reasons this test has no interest in. The observed failure reported 54 against 51: three threads had gone away between the samples, not appeared. This file starts threads in sixteen places, and the SSE stream and reaper threads they leave behind finish whenever they finish, so whether the count holds still depends on the test order and on the scheduler rather than on the behavior under test.The test itself is asking the right question.
setupbuilds its transport withlisten_keepalive_interval: nilprecisely so opening a listen stream spawns no timer, and the point is to hold that guarantee. Only the measurement is wrong, so this compares the set of threads instead: a thread that disappears no longer registers, and a thread that appears still does. Minitest runs these tests serially andopen_listen_streamdrives the SSE body inline rather than on a thread, so a keepalive timer is the only thread that can appear across the two samples.No library code changes.
How Has This Been Tested?
The rewritten assertion was checked for sensitivity before being kept: a temporary probe pointed
open_listen_streamat a transport built withlisten_keepalive_interval: 15and asserted the set difference was not empty. It passed, confirming the assertion still catches a spawned keepalive thread rather than merely never failing. The probe was removed afterwards.The failure did not reproduce locally beforehand, across six seeds of the file on its own and six full-suite runs, which matches a timing-sensitive flake that needs a slower machine.
Breaking Changes
None.
Types of changes
Checklist