Skip to content

Don't wrap loop around waitpid call#489

Merged
ko1 merged 1 commit intoruby:masterfrom
st0012:fix-#485
Feb 21, 2022
Merged

Don't wrap loop around waitpid call#489
ko1 merged 1 commit intoruby:masterfrom
st0012:fix-#485

Conversation

@st0012
Copy link
Member

@st0012 st0012 commented Jan 12, 2022

Process.waitpid by default waits for its child to exit. So there's no need to wrap a loop around it.

What happens in #485 is that the loop keeps running until it's killed by puma with a KILL signal.

Before

[27096] Puma starting in cluster mode...
[27096] * Puma version: 5.5.2 (ruby 3.0.2-p107) ("Zawgyi")
[27096] *  Min threads: 1
[27096] *  Max threads: 1
[27096] *  Environment: development
[27096] *   Master PID: 27096
[27096] *      Workers: 2
[27096] *     Restarts: (✔) hot (✔) phased
[27096] * Listening on http://127.0.0.1:3000
[27096] Use Ctrl-C to stop
DEBUGGER: Attaching after process 27096 fork to child process 27114

# The root process is 27096
# Then Puma forks it and has 27114 

[27096] - Worker 0 (PID: 27114) booted in 0.01s, phase: 0
DEBUGGER[puma: cluster worker 0: 27096 [DebugPuma]#27116]: Attaching after process 27114 fork to child process 27116
[27096] - Worker 1 (PID: 27116) booted in 0.04s, phase: 0

# Puma forks 27114 and gets 27116
# Now the above 2 are Puma's worker processes

^C[27096] - Gracefully shutting down workers...
kill 27114 with TERM
kill 27116 with TERM
kill 27114 with TERM
kill 27116 with TERM

# Process 27116 has now been killed with TERM signal

kill 27114 with TERM
kill 27114 with TERM
kill 27114 with TERM
kill 27114 with TERM
kill 27114 with TERM
kill 27114 with TERM
kill 27114 with TERM
kill 27114 with TERM
kill 27114 with TERM
kill 27114 with TERM
kill 27114 with TERM
kill 27114 with TERM
kill 27114 with TERM
kill 27114 with TERM
kill 27114 with KILL

# Although its child (27116) has been killed, process 27114 still hangs until it's killed by the KILL signal because of the loop

[27096] === puma shutdown: 2022-01-12 12:30:25 +0000 ===
[27096] - Goodbye!
Exiting

After

[25879] Puma starting in cluster mode...
[25879] * Puma version: 5.5.2 (ruby 3.0.2-p107) ("Zawgyi")
[25879] *  Min threads: 1
[25879] *  Max threads: 1
[25879] *  Environment: development
[25879] *   Master PID: 25879
[25879] *      Workers: 2
[25879] *     Restarts: (✔) hot (✔) phased
[25879] * Listening on http://127.0.0.1:3000
[25879] Use Ctrl-C to stop
DEBUGGER: Attaching after process 25879 fork to child process 25904

# The root process is 25879
# Then Puma forks it and has 25904 

[25879] - Worker 0 (PID: 25904) booted in 0.01s, phase: 0
DEBUGGER[puma: cluster worker 0: 25879 [DebugPuma]#25906]: Attaching after process 25904 fork to child process 25906

# Puma forks 25904 and gets 25906
# Now the above 2 are Puma's worker processes

[25879] - Worker 1 (PID: 25906) booted in 0.04s, phase: 0
^C[25879] - Gracefully shutting down workers...
kill 25904 with TERM
kill 25906 with TERM
kill 25904 with TERM
kill 25906 with TERM

# We can see that both of them are killed with TERM signal without issue

[25879] === puma shutdown: 2022-01-12 12:22:29 +0000 ===
[25879] - Goodbye!
Exiting

Reference: https://rubyapi.org/3.1/o/process#method-c-waitpid

@ko1
Copy link
Collaborator

ko1 commented Feb 5, 2022

The patch is okay, but the reason is not correct.
We don't need "loop" because "at_exit" is called the the number of fork call times. Could you change the commit log?

@st0012
Copy link
Member Author

st0012 commented Feb 5, 2022

Do you mean

  • Process.waitpid by default waits for its child to exit. is false?
  • Or The loop was added to iterate through and wait all the child processes, with the assumption that the 'at_exit' is only called once on the main process. But it turned out every parent process can wait for their own children separately. So the loop is not needed.. And thus the Process.waitpid by default waits for its child to exit. is irrelevant here?

What happens in ruby#485 is that the loop keeps running until it's killed by
puma with a `KILL` signal. But that loop is actually not needed.
@st0012
Copy link
Member Author

st0012 commented Feb 12, 2022

Anyway, I've updated the commit message. I think it can be merged.

@ko1
Copy link
Collaborator

ko1 commented Feb 21, 2022

  • If n processes are forked, Process.waitpid should be called n times. This is why I use loop.
  • However, at_exit is called n times and waitpid is called n times in each at_exit block, so loop is not needed.

@ko1 ko1 merged commit b9db10b into ruby:master Feb 21, 2022
@st0012 st0012 deleted the fix-#485 branch February 22, 2022 09:00
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

Successfully merging this pull request may close these issues.

2 participants