diff options
author | Eric Wong <normalperson@yhbt.net> | 2009-02-09 20:42:03 -0800 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2009-02-09 20:51:58 -0800 |
commit | 8fd433875764163eb042a5d7489c2895677ddde1 (patch) | |
tree | 31232437d1ca9ae2a16a500630e9f591e4cb1b08 /lib | |
parent | 07e2f413ab891306d3cdd8e49d0b13acc5e4f679 (diff) | |
download | unicorn-8fd433875764163eb042a5d7489c2895677ddde1.tar.gz |
Like nginx, we'll replace the existing "pid_file" with "pid_file.oldbin" when executing a new binary. We'll also refuse to reexecute a new binary if the ".oldbin" pid file already exists and points to a valid PID.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/unicorn.rb | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/lib/unicorn.rb b/lib/unicorn.rb index 9575944..cacb395 100644 --- a/lib/unicorn.rb +++ b/lib/unicorn.rb @@ -43,6 +43,7 @@ module Unicorn :before_fork => lambda { |server, worker_nr| server.logger.info("worker=#{worker_nr} spawning...") }, + :pid_file => nil, } Worker = Struct.new(:nr, :tempfile) unless defined?(Worker) @@ -93,6 +94,15 @@ module Unicorn io end + if @pid_file + if pid = pid_file_valid?(@pid_file) + raise ArgumentError, "Already running on pid=#{pid} ", + "(or pid_file=#{@pid_file} is stale)" + end + File.open(@pid_file, 'wb') { |fp| fp.syswrite("#{$$}\n") } + at_exit { unlink_pid_file_safe(@pid_file) } + end + # avoid binding inherited sockets, probably not perfect for TCPSockets # but it works for UNIXSockets @listeners -= inherited.map { |io| sock_name(io) } @@ -260,6 +270,19 @@ module Unicorn # reexecutes the @start_ctx with a new binary def reexec check_reexec or return false + + if @pid_file # clear the path for a new pid file + old_pid_file = "#{@pid_file}.oldbin" + if old_pid = pid_file_valid?(old_pid_file) + logger.error "old pid=#{old_pid} running with " \ + "existing pid_file=#{old_pid_file}, refusing rexec" + return + end + File.open(old_pid_file, 'wb') { |fp| fp.syswrite("#{$$}\n") } + at_exit { unlink_pid_file_safe(old_pid_file) } + File.unlink(@pid_file) if File.exist?(@pid_file) + end + pid = spawn_start_ctx if waitpid(pid, WNOHANG) logger.error "rexec pid=#{pid} died with #{$?.exitstatus}" @@ -422,5 +445,24 @@ module Unicorn @workers.keys.each { |pid| kill_worker(signal, pid) } end + # unlinks a PID file at given +path+ if it contains the current PID + # useful as an at_exit handler. + def unlink_pid_file_safe(path) + (File.read(path).to_i == $$ and File.unlink(path)) rescue nil + end + + # returns a PID if a given path contains a non-stale PID file, + # nil otherwise. + def pid_file_valid?(path) + if File.exist?(path) && (pid = File.read(path).to_i) > 1 + begin + kill(0, pid) + return pid + rescue Errno::ESRCH + end + end + nil + end + end end |