Running a Daemon Process on Unix
Problem
You want to run a process in the background with minimal interference from users and the operating system.
Solution
In Ruby 1.9, you can simply call Process.daemon to turn the current process into a daemon. Otherwise, the most reliable way is to use the Daemonize module. Its not available as a gem, but its worth downloading and installing, because it makes it easy and reliable to write a daemon:
#!/usr/bin/ruby -w # daemonize_daemon.rb require empfile require daemonize include Daemonize # Import Daemonize::daemonize into this namespace puts About to daemonize. daemonize # Now you e a daemon process! log = Tempfile.new(daemon.log) loop do log.puts "Im a daemon, doin daemon things." log.flush sleep 5 end
If you run this code at the command line, youll get back a new prompt almost immediately. But there will still be a Ruby process running in the background, writing to a temporary file every five seconds:
$ ./daemonize_daemon.rb About to daemonize. $ ps x | grep daemon 4472 ? S 0:00 ruby daemonize_daemon.rb 4474 pts/2 S+ 0:00 grep daemon $ cat /tmp/daemon.log4472.0 Im a daemon, doin daemon things. Im a daemon, doin daemon things. Im a daemon, doin daemon things.
Since it runs an infinite loop, this daemon process will run until you kill it:
$ kill 4472 $ ps x | grep daemon 4569 pts/2 S+ 0:00 grep daemon
A different daemon might run until some condition is met, or until it receives a Unix signal, or a "stop" message through some interface.
Discussion
A daemon process is one that runs in the background, without any direct user interface at all. Servers are usually daemon processes, but you might also write a daemon to do monitoring or task scheduling.
Rather than replacing your process with a daemon process, you may want to spawn a daemon while continuing with your original work. The best strategy for this is to spawn a subprocess with Kernel#fork.
Rubys fork implementation takes a code block to be run by the subprocess. The code defined after the block is run in the original process. So pass your daemonizing code into fork, and continue with your work in the main body of the code:
#!/usr/bin/ruby -w # daemon_spawn.rb require empfile require daemonize include Daemonize puts "About to daemonize." fork do daemonize log = Tempfile.new(daemon.log) loop do log.puts "Im a daemon, doin daemon things." log.flush sleep 5 end end puts The subprocess has become a daemon. puts "But Im going to stick around for a while." sleep 10 puts "Okay, now Im done."
The Daemonize code fits in a single file, and its licensed under the same terms as Ruby. If you don want to require your users to download and install it, you can just include it with your program. Because the code is short, you can even copy-and-paste the code into a file in your own program.
However, theres also some (less fancy) daemonizing code in the Ruby 1.8 standard library. Its the WEBrick::Daemon class.
#!/usr/bin/ruby # webrick_daemon.rb require empfile require webrick puts About to daemonize. WEBrick::Daemon.start do log = Tempfile.new(daemon.log) loop do log.puts "Im a daemon, doin daemon things." log.flush sleep 5 end end
Its worth examining the simpler daemonizing code in WEBrick::Daemon so that you can see whats going on. Heres the method in question:
def Daemon.start exit!(0) if fork Process::setsid exit!(0) if fork Dir::chdir("/") File::umask(0) STDIN.reopen("/dev/null") STDOUT.reopen("/dev/null", "w") STDERR.reopen("/dev/null", "w") yield if block_given? end
A daemonizer works by forking a new process, letting the original one die, and closing off some of the resources that were available to the original.
Process::setsid disconnects the daemon from the terminal that spawned it. This is why, when your process becomes a daemon process, you get your command line back immediately. We close the original standard input, output, and error and replace them with null streams. We set the working directory and file umask to sensible defaults, regardless of what the daemon inherited from the parent. Then we run the daemon code.
Daemonize::daemonize also sets up signal handlers, calls srand so that the daemon process has a new random number seed, and (optionally) closes any open file handles left around by the original process. It can also retry the fork if it fails because the operating system is running too many processes to create another one.
The fork method, and methods like daemonize that depend on it, are only available on Unix-like systems. On Windows, the win32-process extension provides Windows implementations of methods like fork. The win32-process implementation of fork isn perfect, but its there if you need it. For cross-platform code, we recommend you spawn a thread and run your daemon code in the thread.
See Also
- The Daemonize package (http://grub.ath.cx/daemonize/ )
- If you want to run an Internet server, you might want to use gserver from Rubys standard library; see Recipe 14.14, "Writing an Internet Server"
- A service is the Windows equivalent of a daemon process; see Recipe 20.2, " Creating a Windows Service"
- Recipe 20.3, "Doing Two Things at Once with Threads"
- Both win32-process and win32-service were written by Daniel J. Berger; you can download them from his win32utils project at http://rubyforge.org/projects/win32utils/
- Get win32-process from http://rubyforge.org/projects/win32utils/
Категории