Logo Devoh

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.

and tagged with daemon and ruby