There have been a number of occasions when I have needed to a background process running: image manipulation, content transfer, queuing emails, etc. Initially I wrote the piece which forked off the parent process by hand. Not having read Richard Stephens sections on daemons (Advanced Programming in the Unix Environment) closely enough, I ended up with processes which didn’t get forked enough. Hrmm, this paragraph is going downhill quickly.

Realizing I was wasting a lot of time and making my code look like utter garbage, I began looking for a Ruby library which could replace and correct my forking code. The libraries I found (ctrl-f for daemon on ruby-toolbox) either did way too much, did things antithetical to what I was wanting, or was questionable.

Long story short: I wrote my own. I named it BasicDaemon because it’s just a basic daemon library; well, that and simple_daemon was already taken. It runs in two different ways: 1) you can subclass it and override the run method; 2) you can pass a block to it.

Here’s an example of subclassing BasicDaemon:

!/usr/bin/env ruby

require 'rubygems'
require 'basic_daemon'

class MyDaemon < BasicDaemon
  def run
    foo = open("/tmp/out", "w")

    i = 1

    while true do
      foo.puts "loop: #{i}"
      foo.flush
      sleep 2

      i += 1
    end
  end
end

d = MyDaemon.new

if ARGV[0] == 'start'
  d.start
elsif ARGV[0] == 'stop'
  d.stop
  exit!
elsif ARGV[0] == 'restart'
  d.restart
else
  STDERR.puts "wrong! use start, stop, or restart."
  exit!
end

exit

Here’s the example passing a block:

#!/usr/bin/env ruby

require 'rubygems'
require 'basic_daemon'

basedir = "/tmp" 

d = BasicDaemon.new

# for restarts to work properly, you can't use anonymous blocks. In other
# words, blocks have to be assigned to a variable
process = Proc.new do
  i = 1
  foo = open(basedir + "/out", "w")

  while true do
    foo.puts "loop: #{i}"
    foo.flush
    sleep 2

    i += 1
  end
end

if ARGV[0] == 'start'
  d.start &process
elsif ARGV[0] == 'stop'
  d.stop
  exit!
elsif ARGV[0] == 'restart'
  d.restart &process
else
  STDERR.puts "wrong! Use start, stop, or restart."
  exit!
end

exit

As you can see, both examples do the same thing: they put a loop into the background which logs the number of loops to a file (out) in /tmp. Wheeee!

That’s about it. There are a couple parameters you can set to define where the pidfile will be located or named, but not much more. You can check out the code on GitHub. If you don’t care about checking out the code, you can just install it from gemcutter with the following command:

sudo gem install basic_daemon

And of course, wouldn’t you know it, as soon as I tagged it v1.0.0 and pushed everything out, I realized something I could add to make it better. I guess that’s what v2.0.0 is for.