From 8fd433875764163eb042a5d7489c2895677ddde1 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Mon, 9 Feb 2009 20:42:03 -0800 Subject: Add optional PID file support 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. --- lib/unicorn.rb | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'lib') 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 -- cgit v1.2.3-24-ge0c7