Taking Care of Rails Support Tasks Through Custom Daemons by Tammer Saleh
Some good demo-not-working hijinks in this one.
The speaker is from Thoughtbot (Boston Rails consulting). He gets the gold star for a very well-organized talk. He talked about practical lessons learned from developing a LDAP to ActiveRecord gateway daemon.
No standard way to do a daemon in Ruby
def daemonize
# Important
Kernel.fork and Kernel.exit
Process.setsid
Kernel.fork and Kernel.exit
# Less important
File.umask 0
Dir.chdir '/'
# Release any file descriptors
ObjectSpace.each_object(IO) {|io| io.close rescue nil}
STDIN.open('/dev/null')
STDOUT.open('/dev/null', 'a')
STDERR.open('/dev/null', 'a')
end
Or (shoot! now he tells me after I copied down all the code):
require 'daemon'
Daemons.daemonize
loop {
...
}
What you still need after require 'daemon'
- Rails. Include Rails env. Need to set AR concurrency to true
- Start/stop control. Can write Unix init script in Ruby. (Why didn’t I think of that!) In OS X you can use launchd.
- Ensure only one instance. PidFile class
- Config files. YAML
- Logging. Config log file with rollover
- Security. Use Ruby code to switch over to non-root user and group
How do you test a daemon? Spawn it before your test? Complicated, broken daemons might not die, not encapsulated. Use mocking framework.
Alternatives
- Rake tasks or script/runner
- nohup
- inted & xinetd
Final tips
- Daemonize as soon as possible
- Rescue anything that can fail
- logger.debug a lot