Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

call_as_daemon method don't stop child process #93

Open
sada opened this issue Apr 30, 2024 · 2 comments
Open

call_as_daemon method don't stop child process #93

sada opened this issue Apr 30, 2024 · 2 comments

Comments

@sada
Copy link

sada commented Apr 30, 2024

Your environment

  • ruby -v: ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-linux]
  • daemons (1.4.1)

Describe the bug

Calling Process.waitpid inside the at_exit method will prevent the child process from stopping.

To Reproduce

Script:

Gemfile

# frozen_string_literal: true

source "https://rubygems.org"

gem "daemons"

test_daemon.rb

#!/usr/bin/env ruby

require 'bundler/setup'
Bundler.setup
require 'daemons'

at_exit do
  begin
    Process.waitpid
  rescue Errno::ESRCH, Errno::ECHILD
  end
end

2.times do |i|
  Daemons.run_proc("test_daemon.#{i}") do
    loop do
    end
  end
end

Terminal:

$ test_daemon.rb start

Child process doesn't stop.

$ 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.

  1. Forks another child process and exits first child. This prevents the potential of acquiring a controlling terminal.

daemons/lib/daemons.rb

Lines 43 to 51 in a0e84bc

# 1. Forks a child (and exits the parent process, if needed)
# 2. Becomes a session leader (which detaches the program from
# the controlling terminal).
# 3. Forks another child process and exits first child. This prevents
# the potential of acquiring a controlling terminal.
# 4. Changes the current working directory to "/".
# 5. Clears the file creation mask (sets +umask+ to 0000).
# 6. Closes file descriptors (reopens +$stdout+ and +$stderr+ to point to a logfile if
# possible).

By the way, I encountered this problem when using delayed_job and debug.

Expected behavior

Child processes can be stopped.
Since the first child process should be stopped, I thought it would be a good idea to change the call to the exit! method.

exit if pid = safefork

@thuehlinger
Copy link
Owner

Thank you for the report. I am not sure why you would want to use at_exit in such a scenario, but also I currently cannot follow on why the first child should not exit in this case? Do I understand correctly, that your proposed solution is to replace exit if pid == safefork by exit! if pid == safefork?

@sada
Copy link
Author

sada commented May 1, 2024

exit! if pid == safefork

Yes.
I thought I should stop the first child process so that it is not affected by anything else.

I am not sure why you would want to use at_exit in such a scenario, but also I currently cannot follow on why the first child should not exit in this case?

This issue occurs with delayed_job and debug.
Increase the number of workers using delayed_job's number_of_workers option.

https://github.com/collectiveidea/delayed_job/blob/v4.1.11/lib/delayed/command.rb#L102-L105

Next, loaded debug.

https://github.com/ruby/debug/blob/v1.9.2/lib/debug/local.rb#L106-L107

delayed_job tries to increase the number of workers, but the child process is not stopped, just like the repro program.
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/v7.1.3.2/railties/lib/rails/generators/rails/app/templates/Gemfile.tt#L38

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants