Hi, A couple days ago, I was trying to run Unicorn for Ramaze, and found that `Unicorn.run'' didn''t share the same interface with other Rack handlers, i.e. `options[:Host]'' and `options[:Port]'' Because of this, I can''t just use: Rack::Handler.register(''unicorn'', ''Unicorn'') And invoke this: Ramaze.start(:adapter => ''unicorn'', :port => 8080) To address this, I added a simple wrapper in Innate (which is the core of Ramaze): http://github.com/godfat/innate/commit/9d607f41fdeeca366a9a07155e685ae2605c7025 In short, simply hack the config to: {:listeners => ["#{config[:Host]}:#{config[:Port]}"]} Should we adapt to this interface in Unicorn::Configurator, or provide an additional Rack handle to adapt to this, or maintain this Rack handler in Rack repository, just like the others? http://github.com/rack/rack/tree/master/lib/rack/handler I''m looking forward to your opinion, many thanks! cheers,
"Lin Jen-Shin (aka godfat ??)" <godfat at godfat.org> wrote:> Hi, > > A couple days ago, I was trying to run Unicorn for Ramaze, > and found that `Unicorn.run'' didn''t share the same interface > with other Rack handlers, i.e. `options[:Host]'' and `options[:Port]'' > > Because of this, I can''t just use: > > Rack::Handler.register(''unicorn'', ''Unicorn'') > > And invoke this: > > Ramaze.start(:adapter => ''unicorn'', :port => 8080) > > To address this, I added a simple wrapper in > Innate (which is the core of Ramaze): > > http://github.com/godfat/innate/commit/9d607f41fdeeca366a9a07155e685ae2605c7025 > > In short, simply hack the config to: > > {:listeners => ["#{config[:Host]}:#{config[:Port]}"]} > > Should we adapt to this interface in Unicorn::Configurator, > or provide an additional Rack handle to adapt to this, > or maintain this Rack handler in Rack repository, just like the others? > http://github.com/rack/rack/tree/master/lib/rack/handlerI think making Unicorn.run add to :listeners if :Host or :Port are set will work. I''m not sure if launching Unicorn directly from `rackup'' can ever work right without being too intrusive to the other servers, so having a Unicorn Rack handler in distributed with Rack would''t make sense. Unicorn needs to capture ARGV (before option parsing) and parse its own config file, neither of which is doable out-of-the-box with rackup. Does something like this work? (not tested). diff --git a/lib/unicorn.rb b/lib/unicorn.rb index 0f2b597..d4a00e0 100644 --- a/lib/unicorn.rb +++ b/lib/unicorn.rb @@ -17,6 +17,14 @@ module Unicorn class << self def run(app, options = {}) + # compatibility with other interfaces (Ramaze) + host = options.delete(:Host) + port = options.delete(:Port) + if host || port + port ||= Const::DEFAULT_PORT + host ||= Const::DEFAULT_HOST + (options[:listeners] ||= []) << "#{host}:#{port}" + end HttpServer.new(app, options).start.join end end On the other hand, does Innate make it possible to do transparent upgrades (since rackup does not)? I''ll look into it a bit more later... -- Eric Wong
On Thu, Nov 5, 2009 at 1:07 AM, Eric Wong <normalperson at yhbt.net> wrote:> I think making Unicorn.run add to :listeners if :Host or :Port are set > will work. ?I''m not sure if launching Unicorn directly from `rackup'' can > ever work right without being too intrusive to the other servers, so > having a Unicorn Rack handler in distributed with Rack would''t make > sense. ? Unicorn needs to capture ARGV (before option parsing) and parse > its own config file, neither of which is doable out-of-the-box with > rackup.I see. On the other hand, it would be great if `rackup'' could work with Unicorn directly. Perhaps something like: rackup -r config/unicorn.rb -s unicorn -p 12345 config.ru This would require unicorn config to change to something like: Unicorn::Configurator.instance.instance_eval{ # original config content } Then `Unicorn.run'' should check if Configurator singleton has been configured, and use it instead. I would want this because I have a rackup cluster script. If this would work, then I don''t have to change the existing script to adapt to Unicorn with a -c option, along with changing `rackup'' to `unicorn''. Here''s the script: http://github.com/godfat/app-deploy/blob/master/lib/app-deploy/rack_cluster.rb Here''s an example config for `rack_cluster'': http://github.com/godfat/app-deploy/blob/master/example/rack_cluster.yaml I know I won''t need rack "cluster" once I switch to Unicorn. Perhaps what I should do is just drop rack cluster support, then many things could be simplified.> Does something like this work? (not tested). > > diff --git a/lib/unicorn.rb b/lib/unicorn.rb > index 0f2b597..d4a00e0 100644 > --- a/lib/unicorn.rb > +++ b/lib/unicorn.rb > @@ -17,6 +17,14 @@ module Unicorn > > ? class << self > ? ? def run(app, options = {}) > + ? ? ?# compatibility with other interfaces (Ramaze) > + ? ? ?host = options.delete(:Host) > + ? ? ?port = options.delete(:Port) > + ? ? ?if host || port > + ? ? ? ?port ||= Const::DEFAULT_PORT > + ? ? ? ?host ||= Const::DEFAULT_HOST > + ? ? ? ?(options[:listeners] ||= []) << "#{host}:#{port}" > + ? ? ?end > ? ? ? HttpServer.new(app, options).start.join > ? ? end > ? endYes, work fine at first try. Many thanks for your work! The working `start.rb'' for Ramaze is: require ''unicorn'' Rack::Handler.register(''unicorn'', ''Unicorn'') Ramaze.start(:adapter => ''unicorn'', :port => 7000)> On the other hand, does Innate make it possible to do transparent > upgrades (since rackup does not)? ?I''ll look into it a bit more later...I am not sure what do you mean transparent here,
2009/11/5 Lin Jen-Shin (aka godfat ??) <godfat at godfat.org>:> On Thu, Nov 5, 2009 at 1:07 AM, Eric Wong <normalperson at yhbt.net> wrote: >> On the other hand, does Innate make it possible to do transparent >> upgrades (since rackup does not)? ?I''ll look into it a bit more later... > > I am not sure what do you mean transparent here,Oops, accidentally sent incomplete mail, sorry. I am not sure what do you mean transparent here, but I would guess Innate work better than rackup. :p cheers,
"Lin Jen-Shin (aka godfat ??)" <godfat at godfat.org> wrote:> On Thu, Nov 5, 2009 at 1:07 AM, Eric Wong <normalperson at yhbt.net> wrote: > > I think making Unicorn.run add to :listeners if :Host or :Port are set > > will work. ?I''m not sure if launching Unicorn directly from `rackup'' can > > ever work right without being too intrusive to the other servers, so > > having a Unicorn Rack handler in distributed with Rack would''t make > > sense. ? Unicorn needs to capture ARGV (before option parsing) and parse > > its own config file, neither of which is doable out-of-the-box with > > rackup. > > I see. On the other hand, it would be great if `rackup'' could work with > Unicorn directly. Perhaps something like: > > rackup -r config/unicorn.rb -s unicorn -p 12345 config.ruAs I explained in the other email, this unfortunately can''t ever give you all the features that Unicorn has. I''ve made an effort to keep everything else as compatible and the migration paths as easy as possible.> I would want this because I have a rackup cluster script. > If this would work, then I don''t have to change the existing > script to adapt to Unicorn with a -c option, along with > changing `rackup'' to `unicorn''. > > Here''s the script: > http://github.com/godfat/app-deploy/blob/master/lib/app-deploy/rack_cluster.rb > > Here''s an example config for `rack_cluster'': > http://github.com/godfat/app-deploy/blob/master/example/rack_cluster.yaml > > I know I won''t need rack "cluster" once I switch to Unicorn. > Perhaps what I should do is just drop rack cluster support, > then many things could be simplified.Yeah, it''s probably simpler to just use "unicorn" than to wrap it. It''s really hard use the process management functionality in a libified form since we rely on things like $0 and ARGV. On the other hand, since Unicorn is designed to work with nginx, you can use the same scripts/signals for managing both.> > Does something like this work? (not tested). > > > > diff --git a/lib/unicorn.rb b/lib/unicorn.rb > > index 0f2b597..d4a00e0 100644 > > --- a/lib/unicorn.rb > > +++ b/lib/unicorn.rb > > @@ -17,6 +17,14 @@ module Unicorn > > > > ? class << self > > ? ? def run(app, options = {}) > > + ? ? ?# compatibility with other interfaces (Ramaze) > > + ? ? ?host = options.delete(:Host) > > + ? ? ?port = options.delete(:Port) > > + ? ? ?if host || port > > + ? ? ? ?port ||= Const::DEFAULT_PORT > > + ? ? ? ?host ||= Const::DEFAULT_HOST > > + ? ? ? ?(options[:listeners] ||= []) << "#{host}:#{port}" > > + ? ? ?end > > ? ? ? HttpServer.new(app, options).start.join > > ? ? end > > ? end > > Yes, work fine at first try. Many thanks for your work! > The working `start.rb'' for Ramaze is: > > require ''unicorn'' > Rack::Handler.register(''unicorn'', ''Unicorn'') > Ramaze.start(:adapter => ''unicorn'', :port => 7000) > > > On the other hand, does Innate make it possible to do transparent > > upgrades (since rackup does not)? ?I''ll look into it a bit more later... > > I am not sure what do you mean transparent here,Can you try and see if the USR2 handling of Unicorn allows a transparent upgrade here? If it doesn''t then I don''t think it''s worth supporting an interface that''s crippled compared to using the plain `unicorn'' command. -- Eric Wong
"Lin Jen-Shin (aka godfat ??)" <godfat at godfat.org> wrote:> 2009/11/5 Lin Jen-Shin (aka godfat ??) <godfat at godfat.org>: > > On Thu, Nov 5, 2009 at 1:07 AM, Eric Wong <normalperson at yhbt.net> wrote: > >> On the other hand, does Innate make it possible to do transparent > >> upgrades (since rackup does not)? ?I''ll look into it a bit more later... > > > > I am not sure what do you mean transparent here, > > Oops, accidentally sent incomplete mail, sorry. > > I am not sure what do you mean transparent here, > but I would guess Innate work better than rackup. :pTransparent, zero-downtime upgrades (USR2 + QUIT) that Unicorn can do like nginx[1]. The issue here with rackup is that it changes ARGV with the option parser before Unicorn can get to it. So when Unicorn receives the USR2 signal and respawns itself, it won''t be able to spawn a child with the same command-line options as its parent. Using the "unicorn" script will allow it to always save its ARGV before OptionParser has a chance to mangle it. [1] - http://unicorn.bogomips.org/SIGNALS.html -- Eric Wong
2009/11/5 Eric Wong <normalperson at yhbt.net>:> As I explained in the other email, this unfortunately can''t ever give > you all the features that Unicorn has. > > I''ve made an effort to keep everything else as compatible and the > migration paths as easy as possible.Many, many thanks for your effort on Unicorn. It''s awesome, in all ways. I would switch all services at my working place to Unicorn at some point.> Can you try and see if the USR2 handling of Unicorn allows > a transparent upgrade here? ?If it doesn''t then I don''t think > it''s worth supporting an interface that''s crippled compared > to using the plain `unicorn'' command.I think it does work. This is start.rb: ### #!/usr/bin/env ruby require File.expand_path(''app'', File.dirname(__FILE__)) require ''unicorn'' Rack::Handler.register(''unicorn'', ''Unicorn'') Ramaze.start(:adapter => ''unicorn'', :port => 7000) ### It won''t work if I invoke start.rb like this: $ ruby start.rb (perhaps it''s impossible to get the `ruby'' ?) but it does work if I invoke this way: $ ./start.rb (tested with different debug output in lib/unicorn.rb) On the other hand, `ramaze'' command won''t work, and I guess it''s because it uses `rackup'', which you''ve explained why it won''t. I am wondering.. Could `rackup'' be fixed for this? For instance, use the same way as `unicorn'' in `rackup''? If so, I would be glad to try to fix that in rackup. I would try it later in my free time. cheers,
"Lin Jen-Shin (aka godfat ??)" <godfat at godfat.org> wrote:> 2009/11/5 Eric Wong <normalperson at yhbt.net>: > > As I explained in the other email, this unfortunately can''t ever give > > you all the features that Unicorn has. > > > > I''ve made an effort to keep everything else as compatible and the > > migration paths as easy as possible. > > Many, many thanks for your effort on Unicorn. > It''s awesome, in all ways. I would switch all services > at my working place to Unicorn at some point.Cool, good to know :)> > Can you try and see if the USR2 handling of Unicorn allows > > a transparent upgrade here? ?If it doesn''t then I don''t think > > it''s worth supporting an interface that''s crippled compared > > to using the plain `unicorn'' command. > > I think it does work. This is start.rb: > > ### > #!/usr/bin/env ruby > require File.expand_path(''app'', File.dirname(__FILE__)) > require ''unicorn'' > Rack::Handler.register(''unicorn'', ''Unicorn'') > Ramaze.start(:adapter => ''unicorn'', :port => 7000) > ### > > It won''t work if I invoke start.rb like this: > $ ruby start.rb > (perhaps it''s impossible to get the `ruby'' ?) > but it does work if I invoke this way: > $ ./start.rb > (tested with different debug output in lib/unicorn.rb)Yeah, running "ruby start.rb" throws off $0 unless start.rb is in $PATH. "ruby ./start.rb" should work, too, but it''s ugly. I think there are/were cases where "#!/usr/bin/env ruby" won''t even work as a shebang, too.> On the other hand, `ramaze'' command won''t work, > and I guess it''s because it uses `rackup'', which > you''ve explained why it won''t. > > I am wondering.. Could `rackup'' be fixed for this? > For instance, use the same way as `unicorn'' in `rackup''? > If so, I would be glad to try to fix that in rackup. > I would try it later in my free time.It would require `rackup'' to do a "require ''unicorn''" before it does any option parsing. That would be unnecessarily intrusive if one has Unicorn installed but wants to test with a different server. -- Eric Wong