Add on_force option to shutdown_debug#3671
Conversation
| environment: 'development'.freeze, | ||
| # Number of seconds to wait until we get the first data for the request. | ||
| first_data_timeout: 30, | ||
| force_shutdown_after: -1, |
There was a problem hiding this comment.
This is the default but it lived in the method definition. IMO it should live here because it's a configurable option.
c851fb3 to
d1d8839
Compare
e659047 to
c2797ae
Compare
| if @thread_pool | ||
| if timeout = options[:force_shutdown_after] | ||
| @thread_pool.shutdown timeout.to_f | ||
| else | ||
| @thread_pool.shutdown | ||
| end | ||
| end | ||
| @thread_pool.shutdown options[:force_shutdown_after] |
There was a problem hiding this comment.
- Reading the code I'm quite sure that
@thread_poolwill always be truthy at this point, so we don't need the firstif. - I've moved the default
:force_shutdown_aftervalue (-1) to the config so we no longer need to worry about passing inniland overriding the default in the method definition i.e., we don't need the secondif(andelse).
| if @shutdown_debug == :on_force && !threads.empty? | ||
| shutdown_debug("Shutdown timeout exceeded") |
There was a problem hiding this comment.
Unlike the graceful shutdown case where we print before we join on the threads (which makes sense because the join will wait for as long as needed), here we print after joining - once if and before forcing a shutdown, and then again if and before forcefully killing threads.
06cd4dc to
74fa8dc
Compare
|
@dentarg Any further opinions on this? If not I'm going to go ahead and merge. |
|
Nice How I tested this branch
I did $ echo 'force_shutdown_after 5; shutdown_debug(on_force: true); app { |env| sleep 120; [200, {}, ["OK"]] }' | ruby -rlogger -Ilib ./bin/puma --config /dev/stdin --port 8081 --log-requests --pidfile /tmp/puma -t 4:4
Puma starting in single mode...
* Puma version: 7.1.0 ("Neon Witch")
* Ruby version: ruby 3.4.7 (2025-10-08 revision 7a5688e2a2) +PRISM [arm64-darwin24]
* Min threads: 4
* Max threads: 4
* Environment: development
* PID: 64633
* Listening on http://0.0.0.0:8081
Use Ctrl-C to stop
- Gracefully stopping, waiting for requests to finish
64633: Shutdown timeout exceeded
64633: === Begin thread backtrace dump ===
64633: Thread 1/3: #<Thread:0x000000010431af60 sleep_forever>
64633: /Users/dentarg/src/puma/lib/puma/server.rb:647:in 'Thread#join'
64633: /Users/dentarg/src/puma/lib/puma/server.rb:647:in 'Puma::Server#stop'
64633: /Users/dentarg/src/puma/lib/puma/single.rb:38:in 'Puma::Single#stop_blocked'
64633: /Users/dentarg/src/puma/lib/puma/launcher.rb:286:in 'Puma::Launcher#do_graceful_stop'
64633: /Users/dentarg/src/puma/lib/puma/launcher.rb:450:in 'block in Puma::Launcher#setup_signals'
64633: /Users/dentarg/src/puma/lib/puma/single.rb:66:in 'Thread#join'
64633: /Users/dentarg/src/puma/lib/puma/single.rb:66:in 'Puma::Single#run'
64633: /Users/dentarg/src/puma/lib/puma/launcher.rb:208:in 'Puma::Launcher#run'
64633: /Users/dentarg/src/puma/lib/puma/cli.rb:73:in 'Puma::CLI#run'
64633: ./bin/puma:10:in '<main>'
64633: Thread 2/3: #<Thread:0x000000010483ca20@puma srv tp 001 /Users/dentarg/src/puma/lib/puma/thread_pool.rb:142 sleep>
64633: /dev/stdin:1:in 'Kernel#sleep'
64633: /dev/stdin:1:in 'block in Puma::DSL#_load_from'
64633: /Users/dentarg/src/puma/lib/puma/commonlogger.rb:47:in 'Puma::CommonLogger#call'
64633: /Users/dentarg/src/puma/lib/puma/configuration.rb:301:in 'Puma::Configuration::ConfigMiddleware#call'
64633: /Users/dentarg/src/puma/lib/puma/request.rb:103:in 'block in Puma::Request#handle_request'
64633: /Users/dentarg/src/puma/lib/puma/thread_pool.rb:356:in 'Puma::ThreadPool#with_force_shutdown'
64633: /Users/dentarg/src/puma/lib/puma/request.rb:102:in 'Puma::Request#handle_request'
64633: /Users/dentarg/src/puma/lib/puma/server.rb:503:in 'Puma::Server#process_client'
64633: /Users/dentarg/src/puma/lib/puma/server.rb:262:in 'block in Puma::Server#run'
64633: /Users/dentarg/src/puma/lib/puma/thread_pool.rb:183:in 'block in Puma::ThreadPool#spawn_thread'
64633: Thread 3/3: #<Thread:0x0000000104831b48@puma srv /Users/dentarg/src/puma/lib/puma/server.rb:281 run>
64633: /Users/dentarg/src/puma/lib/puma/thread_pool.rb:433:in 'Thread#backtrace'
64633: /Users/dentarg/src/puma/lib/puma/thread_pool.rb:433:in 'block in Puma::ThreadPool#shutdown_debug'
64633: /Users/dentarg/src/puma/lib/puma/thread_pool.rb:431:in 'Array#each'
64633: /Users/dentarg/src/puma/lib/puma/thread_pool.rb:431:in 'Enumerable#each_with_index'
64633: /Users/dentarg/src/puma/lib/puma/thread_pool.rb:431:in 'Puma::ThreadPool#shutdown_debug'
64633: /Users/dentarg/src/puma/lib/puma/thread_pool.rb:398:in 'Puma::ThreadPool#shutdown'
64633: /Users/dentarg/src/puma/lib/puma/server.rb:625:in 'Puma::Server#graceful_shutdown'
64633: /Users/dentarg/src/puma/lib/puma/server.rb:425:in 'Puma::Server#handle_servers'
64633: /Users/dentarg/src/puma/lib/puma/server.rb:283:in 'block in Puma::Server#run'
64633: === End thread backtrace dump ===
2025-11-25 23:42:36 +0100 Rack app ("GET /" - (127.0.0.1)): #<Puma::ThreadPool::ForceShutdown: Puma::ThreadPool::ForceShutdown>
Detected force shutdown of a thread
zsh: done echo |
zsh: terminated ruby -rlogger -Ilib ./bin/puma --config /dev/stdin --port 8081 --log-requestsIn the main branch, threads backtraces are printed but then Puma waits for
|
dentarg
left a comment
There was a problem hiding this comment.
I think we should try to avoid capture_io
|
I rebased this. I'll save a link to the commit before rebase from Nov 28, 2025, for anyone curious. be6e624 |
|
@dentarg Thanks! I completely forgot about this. I'll merge soon. |
|
I started to look at the failing tests after I rebased, but I got distracted. What's up with JRuby/TruffleRuby? A bit telling that all of the JVM based rubies fail? |
f60582b to
36256ac
Compare
1518355 to
4c2e3a3
Compare
Requested changes have been addressed.
Resolved. TL;DR: |
|
Thank you for solving this @joshuay03! If not sooner, I'll take this for spin when we have it in a release. |
Description
Closes #3666
Your checklist for this pull request
[ci skip]to the title of the PR.#issue" to the PR description or my commit messages.