Cleanly Terminating Ruby Daemons
Recently, I have been spending a lot of time working on a daemon written in Ruby. I'm using the Daemons gem as a starting point as it does a nice job of taking care of the nitty-gritty details of spawning threads, dealing with PID files, and providing a simple interface for starting and stopping the daemon.
The stopping part, however, has been somewhat problematic for me as the daemon sometimes continues to run. Somewhere along the line the signal is being swallowed, never to fulfill its destiny as the mortal messenger that it is. Sometimes you may also want certain code to finish executing before the daemon exits. Either way, it would be nice to have a little more control over the shutdown process rather than just aborting it mid-stride.
I have found a solution that solves both of these issues. Let's start by looking at a barebones daemon that will just sit quietly in the background until told to do otherwise.
Daemons.run_proc('sleeper, { :log_output => true }') do puts 'Started' loop do puts 'Sleeping' sleep 1 end puts 'Stopped' end
In this case there shouldn't be a problem stopping the daemon, but we really don't have much control over the process. Here's what the output looks if we start it up and let it run for a few seconds:
Started Sleeping Sleeping Sleeping
You'll notice that "Stopped" is never output, but the daemon is abruptly terminated right inside the loop
instead. To get around this, we can use trap
to catch the TERM signal and handle it a little more gracefully.
Daemons.run_proc('sleeper', { :log_output => true }) do puts 'Started' run = true trap 'TERM', lambda { run = false } while run puts 'Sleeping' sleep 1 end puts 'Stopped' end
Now our output looks just as it should.
Started Sleeping Sleeping Sleeping Stopped
This allows us to cleanly finish up whatever we're doing and make a graceful exit.