summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2010-02-17 19:24:09 -0800
committerEric Wong <normalperson@yhbt.net>2010-02-18 13:34:13 -0800
commit8963e87841501c8e79b8434f8887e0d3a78b580c (patch)
tree0c85fc9b6ed9c1c06c70ab4115e87c7c836ac9e8
parentae0c39e09b27e953f41b2714c5d194a9e9a00da2 (diff)
If preload_app is true and Unicorn is HUP-ed with a bad
config.ru, then it would be possible to have Unicorn in a bad
state and constantly throw 500 errors.

We now detect syntax and load errors since they're likely to
appear in modified Rackup files, and will restore the original
app if reloading failed.
-rw-r--r--lib/unicorn.rb4
-rwxr-xr-xt/t0001-reload-bad-config.sh52
2 files changed, 55 insertions, 1 deletions
diff --git a/lib/unicorn.rb b/lib/unicorn.rb
index e8d869b..6dec03e 100644
--- a/lib/unicorn.rb
+++ b/lib/unicorn.rb
@@ -731,6 +731,7 @@ module Unicorn
     end
 
     def load_config!
+      loaded_app = app
       begin
         logger.info "reloading config_file=#{config.config_file}"
         config[:listeners].replace(init_listeners)
@@ -741,9 +742,10 @@ module Unicorn
         self.app = orig_app
         build_app! if preload_app
         logger.info "done reloading config_file=#{config.config_file}"
-      rescue => e
+      rescue StandardError, LoadError, SyntaxError => e
         logger.error "error reloading config_file=#{config.config_file}: " \
                      "#{e.class} #{e.message}"
+        self.app = loaded_app
       end
     end
 
diff --git a/t/t0001-reload-bad-config.sh b/t/t0001-reload-bad-config.sh
new file mode 100755
index 0000000..e1393ae
--- /dev/null
+++ b/t/t0001-reload-bad-config.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+. ./test-lib.sh
+t_plan 7 "reload config.ru error with preload_app true"
+
+t_begin "setup and start" && {
+        unicorn_setup
+        rtmpfiles ru
+
+        cat > $ru <<\EOF
+use Rack::ContentLength
+use Rack::ContentType, "text/plain"
+x = { "hello" => "world" }
+run lambda { |env| [ 200, {}, [ x.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 "introduce syntax error in rackup file" && {
+        echo '...' >> $ru
+}
+
+t_begin "reload signal succeeds" && {
+        kill -HUP $unicorn_pid
+        while ! egrep '(done|error) reloading' $r_err >/dev/null
+        do
+                sleep 1
+        done
+
+        grep 'error 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_begin "check stderr" && {
+        check_stderr
+}
+
+t_done