diff options
author | Eric Wong <normalperson@yhbt.net> | 2009-12-26 17:04:57 -0800 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2009-12-26 17:15:11 -0800 |
commit | 5eea32764571b721cd1a89cf9ebfa853c621ac9e (patch) | |
tree | 7aae0814fe23d06945b92ee9158b3f02bbd37b4b | |
parent | 643994afcdbd4121c0d131a87052cdd17d40e54f (diff) | |
download | unicorn-5eea32764571b721cd1a89cf9ebfa853c621ac9e.tar.gz |
This behavior change also means our grandparent (launched from a controlling terminal or script) will wait until the master process is ready before returning. Thanks to IƱaki Baz Castillo for the initial implementations and inspiration.
-rwxr-xr-x | bin/unicorn | 2 | ||||
-rwxr-xr-x | bin/unicorn_rails | 2 | ||||
-rw-r--r-- | lib/unicorn.rb | 9 | ||||
-rw-r--r-- | lib/unicorn/launcher.rb | 37 | ||||
-rw-r--r-- | test/exec/test_exec.rb | 2 |
5 files changed, 39 insertions, 13 deletions
diff --git a/bin/unicorn b/bin/unicorn index 651c2ff..5af021d 100755 --- a/bin/unicorn +++ b/bin/unicorn @@ -161,5 +161,5 @@ if $DEBUG }) end -Unicorn::Launcher.daemonize! if daemonize +Unicorn::Launcher.daemonize!(options) if daemonize Unicorn.run(app, options) diff --git a/bin/unicorn_rails b/bin/unicorn_rails index 4a22a8c..b1458fc 100755 --- a/bin/unicorn_rails +++ b/bin/unicorn_rails @@ -202,6 +202,6 @@ end if daemonize options[:pid] = rails_pid - Unicorn::Launcher.daemonize! + Unicorn::Launcher.daemonize!(options) end Unicorn.run(app, options) diff --git a/lib/unicorn.rb b/lib/unicorn.rb index 71d5994..ae05f03 100644 --- a/lib/unicorn.rb +++ b/lib/unicorn.rb @@ -25,7 +25,8 @@ module Unicorn class << self def run(app, options = {}) - HttpServer.new(app, options).start.join + ready_pipe = options.delete(:ready_pipe) + HttpServer.new(app, options).start.join(ready_pipe) end end @@ -313,7 +314,7 @@ module Unicorn # (or until a termination signal is sent). This handles signals # one-at-a-time time and we'll happily drop signals in case somebody # is signalling us too often. - def join + def join(ready_pipe = nil) # this pipe is used to wake us up from select(2) in #join when signals # are trapped. See trap_deferred init_self_pipe! @@ -324,6 +325,10 @@ module Unicorn trap(:CHLD) { |sig_nr| awaken_master } proc_name 'master' logger.info "master process ready" # test_exec.rb relies on this message + if ready_pipe + ready_pipe.syswrite($$.to_s) + ready_pipe.close + end begin loop do reap_all_workers diff --git a/lib/unicorn/launcher.rb b/lib/unicorn/launcher.rb index 1229b84..2d6ad97 100644 --- a/lib/unicorn/launcher.rb +++ b/lib/unicorn/launcher.rb @@ -19,21 +19,42 @@ class Unicorn::Launcher # the directory it was started in when being re-executed # to pickup code changes if the original deployment directory # is a symlink or otherwise got replaced. - def self.daemonize! + def self.daemonize!(options = {}) $stdin.reopen("/dev/null") + $stdin.sync = true # may not do anything... # We only start a new process group if we're not being reexecuted # and inheriting file descriptors from our parent unless ENV['UNICORN_FD'] - exit if fork - Process.setsid - exit if fork + # grandparent - reads pipe, exits when master is ready + # \_ parent - exits immediately ASAP + # \_ unicorn master - writes to pipe when ready - # $stderr/$stderr can/will be redirected separately in the Unicorn config - Unicorn::Configurator::DEFAULTS[:stderr_path] = "/dev/null" - Unicorn::Configurator::DEFAULTS[:stdout_path] = "/dev/null" + rd, wr = IO.pipe + grandparent = $$ + if fork + wr.close # grandparent does not write + else + rd.close # unicorn master does not read + Process.setsid + exit if fork # parent dies now + end + + if grandparent == $$ + # this will block until HttpServer#join runs (or it dies) + master_pid = rd.sysread(16).to_i + exit!(1) unless master_pid > 1 + exit 0 + else # unicorn master process + options[:ready_pipe] = wr + # $stderr/$stderr can/will be redirected separately in the + # Unicorn config + Unicorn::Configurator::DEFAULTS[:stderr_path] = "/dev/null" + Unicorn::Configurator::DEFAULTS[:stdout_path] = "/dev/null" + + # returns so Unicorn.run can happen + end end - $stdin.sync = $stdout.sync = $stderr.sync = true end end diff --git a/test/exec/test_exec.rb b/test/exec/test_exec.rb index fc0719b..24ba856 100644 --- a/test/exec/test_exec.rb +++ b/test/exec/test_exec.rb @@ -805,7 +805,7 @@ EOF exec($unicorn_bin, "-D", "-l#{@addr}:#{@port}", "-c#{ucfg.path}") end pid, status = Process.waitpid2(pid) - assert status.success?, "original process exited successfully" + assert ! status.success?, "original process exited successfully" sleep 1 # can't waitpid on a daemonized process :< assert err.stat.size > 0 end |