Autonomous Machine

Posts tagged with POSIX

Killing Processes in Ruby

Killing a process in Ruby is pretty straight forward. You just need to know the process ID for the process, and which signal you want to send:

Process.kill('INT', pid) # where pid is the process id of the process to be killed

A list of signals supported by your system is available from Signal.list, but knowing which one to use is easier after looking at the definitions. I typically use SIGINT (you can just use INT in Ruby) to kill processes.

Something that I've always found messy (and error prone) is cleaning up a bunch of dependent processes that were spawned as part of an automated script. A common case for this is running integration tests where you have at least one process that is the server, a process that is running tests against that server, and potentially other helper processes for web browser automation, etc.

This is a hard problem because it isn't easy to know the process IDs for all of the child processes of a script. It may spawn additional processes, and commonly the process IDs returned to Ruby when spawning processes end up being incorrect due to redirection or process replacement.

UNIX!

It turns out that there is a simple UNIX solution to this problem: process groups. By sending a signal to a process group instead of a single process ID, we are able to send it to all of a script's child processes without knowing their individual process IDs.

To do this, use Process.getpgrp to get the process group of the current process, and pass it to Process.kill as a negative number, which indicates the argument is a process group and not a process ID. And since the current process is going to receive the signal as well, use trap to catch it and provide a clean exit. In a script used for testing, use a non-zero exit status if any tests failed.

trap("INT") do
  exit
end
Process.kill('INT', -Process.getpgrp)

It appears that it is also possible to use 0 as the second argument to Process.kill, and have the same behavior. For the sake of clarity, though, I prefer the former option.

Everything in this article should work in POSIX environments, but I have no idea if it will work on Windows.

  • June 02, 2011
  • Article
  • POSIX, Ruby