Keep a stub WEBrick from hanging the suite on Ruby 4.0 - #669
Merged
Conversation
CI jobs on Ruby 4.0 intermittently produced no output after an `ember build` until the 15-minute cap cancelled them (e.g. run 33876168453, jobs `build (4.0, 8.1, 7.0.0)` and `build (4.0, main, 7.0.0)`); no job on Ruby 3.3 or 3.4 ever did. The hang is in `spec/lib/ember_cli/dev_server_spec.rb`: `NullServer#listen` starts WEBrick in a new thread and returns immediately, and the example's `after` hook then calls `GenericServer#shutdown` and joins the thread. `shutdown` is a no-op until `#start` has set up its shutdown pipe, so when the thread has not run yet the server boots afterwards and loops in `IO.select` forever, and the join never returns. On Ruby 4.0 a new thread usually has not run by then: a standalone loop of the same steps hung 187 of 300 times on Ruby 4.0.6 and 0 of 300 times on Ruby 3.3.6, and the spec file alone hung 23 of 25 runs on Ruby 4.0.6 before this change and 0 of 25 after it. The `:js` timeout added in #668 could not catch this because these are plain examples, and their progress dots never reached the log: the runner only flushes complete lines, which is why the jobs looked stuck right after the build output. Wait until WEBrick reports `:Running` before `listen` returns, so that `shutdown` always reaches a server loop that can be stopped. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FRn3BbAGhG1oWGbNkSHkvA
tricknotes
deleted the
claude/github-actions-error-investigation-8nkr1o
branch
September 5, 2026 13:08
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.
Problem
CI jobs on Ruby 4.0 intermittently stop producing output after an
ember buildand run until the 15-minute cap cancels them, e.g. run 33876168453 (build (4.0, 8.1, 7.0.0)andbuild (4.0, main, 7.0.0)), and before it runs 33875447042, 33871839705, 33869563469 and 33869331315. Every cancelled job in those runs is a Ruby 4.0 job; no Ruby 3.3 / 3.4 job ever hung. The--disable-dev-shm-usage/:jstimeout from #668 did not stop it (the run above is the merge of #668).Cause
Reproduced locally with Ruby 4.0.6 and a watchdog that dumps every thread's backtrace once an example runs for 90 seconds. The main thread was stuck here:
while the WEBrick thread it joins sat in
IO.selectinsideWEBrick::GenericServer#startwithstatus == :Running.NullServer#listenstarts WEBrick withThread.new { @server.start }and returns at once; the example'safterhook then callsGenericServer#shutdownand joins the thread.GenericServer#shutdownonly works once#starthas set up its shutdown pipe (stoponly flips:Runningto:Shutdown, andalarm_shutdown_pipedoes nothing while@shutdown_pipeis nil). When the thread has not run yet,shutdownis a no-op, the server boots afterwards and loops inIO.selectforever, and the join never returns. On Ruby 4.0 a freshly created thread usually has not run by the time the example finishes.Measured with a standalone loop of the same steps (boot WEBrick in a thread, connect once,
shutdown,joinwith a 2s limit):The
:jstimeout from #668 cannot catch this: these are plain examples. And the progress dots of the examples that ran after the lastember buildnever reached the job log, because the Actions runner only flushes complete lines, which is why the jobs looked stuck right after the build output.Fix
NullServer#listennow waits until WEBrick reports:Running(with a 5-second limit) before returning, soshutdownalways reaches a server loop that can be stopped.Verification
Ruby 4.0.6, Rails 8.1, Ember 7.0.0:
rspec spec/lib/ember_cli/dev_server_spec.rb, 25 runs with a 25s limitbin/rake(full suite)Also green on Ruby 3.3.6.
🤖 Generated with Claude Code
https://claude.ai/code/session_01FRn3BbAGhG1oWGbNkSHkvA
Generated by Claude Code