diff options
-rwxr-xr-x | bin/unicorn | 40 | ||||
-rw-r--r-- | lib/unicorn.rb | 38 | ||||
-rwxr-xr-x | t/t0002-config-conflict.sh | 49 |
3 files changed, 92 insertions, 35 deletions
diff --git a/bin/unicorn b/bin/unicorn index 5af021d..0da0869 100755 --- a/bin/unicorn +++ b/bin/unicorn @@ -108,49 +108,19 @@ opts = OptionParser.new("", 24, ' ') do |opts| opts.parse! ARGV end -config = ARGV[0] || "config.ru" -abort "configuration file #{config} not found" unless File.exist?(config) +ru = ARGV[0] || "config.ru" +abort "configuration file #{ru} not found" unless File.exist?(ru) -if config =~ /\.ru$/ +if ru =~ /\.ru$/ # parse embedded command-line options in config.ru comments - if File.open(config, "rb") { |fp| fp.sysread(fp.stat.size) } =~ /^#\\(.*)/ + if File.open(ru, "rb") { |fp| fp.sysread(fp.stat.size) } =~ /^#\\(.*)/ opts.parse! $1.split(/\s+/) end end require 'pp' if $DEBUG -app = lambda do || - # require Rack as late as possible in case $LOAD_PATH is modified - # in config.ru or command-line - inner_app = case config - when /\.ru$/ - raw = File.open(config, "rb") { |fp| fp.sysread(fp.stat.size) } - raw.sub!(/^__END__\n.*/, '') - eval("Rack::Builder.new {(#{raw}\n)}.to_app", nil, config) - else - require config - Object.const_get(File.basename(config, '.rb').capitalize) - end - pp({ :inner_app => inner_app }) if $DEBUG - case ENV["RACK_ENV"] - when "development" - Rack::Builder.new do - use Rack::CommonLogger, $stderr - use Rack::ShowExceptions - use Rack::Lint - run inner_app - end.to_app - when "deployment" - Rack::Builder.new do - use Rack::CommonLogger, $stderr - run inner_app - end.to_app - else - inner_app - end -end - +app = Unicorn.builder(ru) listeners << "#{host}:#{port}" if set_listener if $DEBUG diff --git a/lib/unicorn.rb b/lib/unicorn.rb index 6dec03e..d3e9c3d 100644 --- a/lib/unicorn.rb +++ b/lib/unicorn.rb @@ -27,6 +27,44 @@ module Unicorn def run(app, options = {}) HttpServer.new(app, options).start.join end + + # This returns a lambda to pass in as the app, this does not "build" the + # app (which we defer based on the outcome of "preload_app" in the + # Unicorn config). The returned lambda will be called when it is + # time to build the app. + def builder(ru) + lambda do || + inner_app = case ru + when /\.ru$/ + raw = File.open(ru, "rb") { |fp| fp.sysread(fp.stat.size) } + raw.sub!(/^__END__\n.*/, '') + eval("Rack::Builder.new {(#{raw}\n)}.to_app", TOPLEVEL_BINDING, ru) + else + require ru + Object.const_get(File.basename(ru, '.rb').capitalize) + end + + pp({ :inner_app => inner_app }) if $DEBUG + + # return value, matches rackup defaults based on env + case ENV["RACK_ENV"] + when "development" + Rack::Builder.new do + use Rack::CommonLogger, $stderr + use Rack::ShowExceptions + use Rack::Lint + run inner_app + end.to_app + when "deployment" + Rack::Builder.new do + use Rack::CommonLogger, $stderr + run inner_app + end.to_app + else + inner_app + end + end + end end # This is the process manager of Unicorn. This manages worker diff --git a/t/t0002-config-conflict.sh b/t/t0002-config-conflict.sh new file mode 100755 index 0000000..d7b2181 --- /dev/null +++ b/t/t0002-config-conflict.sh @@ -0,0 +1,49 @@ +#!/bin/sh +. ./test-lib.sh +t_plan 6 "config variables conflict with preload_app" + +t_begin "setup and start" && { + unicorn_setup + rtmpfiles ru rutmp + + cat > $ru <<\EOF +use Rack::ContentLength +use Rack::ContentType, "text/plain" +config = ru = { "hello" => "world" } +run lambda { |env| [ 200, {}, [ ru.inspect << "\n" ] ] } +EOF + echo 'preload_app true' >> $unicorn_config + unicorn -D -c $unicorn_config $ru + unicorn_wait_start +} + +t_begin "hit with curl" && { + out=$(curl -sSf http://$listen/) + test x"$out" = x'{"hello"=>"world"}' +} + +t_begin "modify rackup file" && { + sed -e 's/world/WORLD/' < $ru > $rutmp + mv $rutmp $ru +} + +t_begin "reload signal succeeds" && { + kill -HUP $unicorn_pid + while ! egrep '(done|error) reloading' < $r_err >/dev/null + do + sleep 1 + done + + grep 'done reloading' $r_err >/dev/null +} + +t_begin "hit with curl" && { + out=$(curl -sSf http://$listen/) + test x"$out" = x'{"hello"=>"WORLD"}' +} + +t_begin "killing succeeds" && { + kill $unicorn_pid +} + +t_done |