after_fork_parent method waits for all child processes to stop
Your environment
-
ruby -v: ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-linux] -
rdbg -v: rdbg 1.9.2
Describe the bug
I'm using delayed_job. When I tried to increase the number of workers, the number of workers did not increase because the child process did not stop.
The problem was due to Process.waitpid below.
https://github.com/ruby/debug/blob/master/lib/debug/local.rb#L106-L107
To Reproduce
delayed_job uses daemons.
Script:
Gemfile
# frozen_string_literal: true
source "https://rubygems.org"
gem "debug", platforms: %i[ mri windows ]
gem "daemons"
test_daemon.rb
#!/usr/bin/env ruby
require 'bundler/setup'
Bundler.setup
require 'debug'
require 'daemons'
2.times do |i|
Daemons.run_proc("test_daemon.#{i}") do
loop do
end
end
end
Terminal:
$ test_daemon.rb start
Child processes do not stop and workers do not increase.
$ ps aux
--snip--
sada 14719 1.8 0.2 177232 37168 pts/6 Sl+ 17:01 0:00 ruby ./test_daemon.rb start
sada 14735 0.0 0.2 177232 33832 ? Ssl 17:01 0:00 ruby ./test_daemon.rb start
sada 14737 94.6 0.2 180308 37540 ? Rl 17:01 0:08 test_daemon.0
The following fork operations are no longer possible.
- Forks another child process and exits first child. This prevents the potential of acquiring a controlling terminal.
https://github.com/thuehlinger/daemons/blob/a0e84bcebe8b872ff59e1e0aa10e1f1718a933b1/lib/daemons.rb#L43-L51
Also, in Rails development, debug is loaded by default, When starting delayed_job, unexpected block is caused by this issue.
https://github.com/rails/rails/blob/5e0c7388a378f4beb5368217a8f57f3c1bfbfabe/railties/lib/rails/generators/rails/app/templates/Gemfile.tt#L36
Expected behavior
Child processes other than debug do not wait to stop.
👋 I don't have good context around the forking mechanism, but as a workaround you can add require: "debug/prelude" after gem "debug". Then the debugger won't be activated by default and cause the problem, but you can still use debugger or binding.break breakpoints.
👋 I don't have good context around the forking mechanism, but as a workaround you can add
require: "debug/prelude"aftergem "debug". Then the debugger won't be activated by default and cause the problem, but you can still usedebuggerorbinding.breakbreakpoints.
Thank you.
I added require: "debug/prelude".
I have confirmed that adding the above results in the expected behavior.
Script:
Gemfile
# frozen_string_literal: true
source "https://rubygems.org"
gem "debug", platforms: %i[ mri windows ], require: "debug/prelude"
gem "daemons"
test_daemons.rb
#!/usr/bin/env ruby
require 'bundler/setup'
Bundler.setup
require 'daemons'
2.times do |i|
Daemons.run_proc("test_daemon.#{i}") do
loop do
end
end
end
Terminal:
$ ./test_daemon.rb start
$ ps aux | grep test_daemon
sada 2303 99.8 0.1 106720 31088 ? R 16:03 6:04 test_daemon.0
sada 2305 99.8 0.1 106720 31092 ? R 16:03 6:04 test_daemon.1
sada 2308 0.0 0.0 7488 656 pts/2 S+ 16:09 0:00 grep test_daemon
Thank you. I didn't check daemons yet, so it can be a bug for tracking processes.