From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: AS14383 205.234.109.0/24 X-Spam-Status: No, score=-0.5 required=5.0 tests=AWL,MSGID_FROM_MTA_HEADER, RP_MATCHES_RCVD shortcircuit=no autolearn=unavailable version=3.3.2 Path: news.gmane.org!not-for-mail From: Eric Wong Newsgroups: gmane.comp.lang.ruby.unicorn.general Subject: Re: "unicorn -D" always returns 0 "success" (even when failed to load) Date: Sat, 26 Dec 2009 17:31:15 -0800 Message-ID: <20091227013115.GA28140@dcvr.yhbt.net> References: <200912260529.45530.ibc@aliax.net> <20091226061652.GB22433@dcvr.yhbt.net> <200912261647.51764.ibc@aliax.net> <200912261923.24626.ibc@aliax.net> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable X-Trace: ger.gmane.org 1261877487 20728 80.91.229.12 (27 Dec 2009 01:31:27 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Sun, 27 Dec 2009 01:31:27 +0000 (UTC) To: unicorn list Original-X-From: mongrel-unicorn-bounces@rubyforge.org Sun Dec 27 02:31:20 2009 Return-path: Envelope-to: gclrug-mongrel-unicorn@m.gmane.org X-Original-To: mongrel-unicorn@rubyforge.org Delivered-To: mongrel-unicorn@rubyforge.org Content-Disposition: inline In-Reply-To: <200912261923.24626.ibc@aliax.net> User-Agent: Mutt/1.5.18 (2008-05-17) X-BeenThere: mongrel-unicorn@rubyforge.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: mongrel-unicorn-bounces@rubyforge.org Errors-To: mongrel-unicorn-bounces@rubyforge.org Xref: news.gmane.org gmane.comp.lang.ruby.unicorn.general:255 Archived-At: Received: from rubyforge.org ([205.234.109.19]) by lo.gmane.org with esmtp (Exim 4.50) id 1NOhyY-0003Ny-2v for gclrug-mongrel-unicorn@m.gmane.org; Sun, 27 Dec 2009 02:31:18 +0100 Received: from rubyforge.org (rubyforge.org [127.0.0.1]) by rubyforge.org (Postfix) with ESMTP id ED77716782B6; Sat, 26 Dec 2009 20:31:17 -0500 (EST) Received: from dcvr.yhbt.net (dcvr.yhbt.net [64.71.152.64]) by rubyforge.org (Postfix) with ESMTP id 40E99185828D for ; Sat, 26 Dec 2009 20:31:16 -0500 (EST) Received: from localhost (unknown [127.0.2.5]) by dcvr.yhbt.net (Postfix) with ESMTP id AF3A51F540; Sun, 27 Dec 2009 01:31:15 +0000 (UTC) I=F1aki Baz Castillo wrote: > El S=E1bado, 26 de Diciembre de 2009, I=F1aki Baz Castillo escribi=F3: > > El S=E1bado, 26 de Diciembre de 2009, Eric Wong escribi=F3: > > > Interesting, I could be tempted to accept this with a few changes... > > > > > > Process.detach() spawns a background Thread. Having running threads > > > before forking won't fly with certain OS threading libraries (some > > > versions of FreeBSD, I believe, check MRI Redmine for some open bugs). > > = > > Yes, but there is a problem: > > Imagine I don't use Process.detach and the master process ends when loa= ds > > the rack application (due to a typo or due to an error in unicorn conf > > file). Then the master process would remain visible/alive but as zombi= e. > > If so, when the controller process sends signal 0 to check the master > > process it will always receive 'true' (a zombie process is a process w= hich > > can receive signals, it's does exist). > = > Hi, I've improved it a bit with your suggestions and also simplified > it a lot. Now there is no a "controller process". Instead, if > "Unicorn.run" raises then master process rescues the exception and > sends USR1 to parent process so it exists with 1. Hi, I realized Unicorn.run inside the daemonize method doesn't work. The daemonize method is also used by Rainbows! (and Zbatery). However, I've reimplemented much of your idea here so it does not involve sleeping at all, but rather shares a pipe with the grandparent (started by the user) and Unicorn master process. The added benefit of using a pipe is that there's no fuzzy sleeping involved at or grace periods to worry about, too. Also pushed out to the "ready_pipe" branch of git://git.bogomips.org/unicorn.git Let me know how it goes. If everything looks good, I'll consider merging for 0.96.0. >>From 5eea32764571b721cd1a89cf9ebfa853c621ac9e Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sat, 26 Dec 2009 17:04:57 -0800 Subject: [PATCH] exit with failure if master dies when daemonized MIME-Version: 1.0 Content-Type: text/plain; charset=3DUTF-8 Content-Transfer-Encoding: 8bit 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=F1aki Baz Castillo for the initial implementations and inspiration. --- bin/unicorn | 2 +- bin/unicorn_rails | 2 +- lib/unicorn.rb | 9 +++++++-- lib/unicorn/launcher.rb | 37 +++++++++++++++++++++++++++++-------- 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] =3D 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 =3D {}) - HttpServer.new(app, options).start.join + ready_pipe =3D 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 =3D nil) # this pipe is used to wake us up from select(2) in #join when signa= ls # 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 mes= sage + 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 =3D {}) $stdin.reopen("/dev/null") + $stdin.sync =3D 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 c= onfig - Unicorn::Configurator::DEFAULTS[:stderr_path] =3D "/dev/null" - Unicorn::Configurator::DEFAULTS[:stdout_path] =3D "/dev/null" + rd, wr =3D IO.pipe + grandparent =3D $$ + 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 =3D=3D $$ + # this will block until HttpServer#join runs (or it dies) + master_pid =3D rd.sysread(16).to_i + exit!(1) unless master_pid > 1 + exit 0 + else # unicorn master process + options[:ready_pipe] =3D wr + # $stderr/$stderr can/will be redirected separately in the + # Unicorn config + Unicorn::Configurator::DEFAULTS[:stderr_path] =3D "/dev/null" + Unicorn::Configurator::DEFAULTS[:stdout_path] =3D "/dev/null" + + # returns so Unicorn.run can happen + end end - $stdin.sync =3D $stdout.sync =3D $stderr.sync =3D 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 =3D 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 -- = Eric Wong _______________________________________________ Unicorn mailing list - mongrel-unicorn@rubyforge.org http://rubyforge.org/mailman/listinfo/mongrel-unicorn Do not quote signatures (like this one) or top post when replying