about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2013-10-18 18:27:28 +0000
committerEric Wong <normalperson@yhbt.net>2013-10-18 18:27:28 +0000
commit2c5b5bb7a3bab2d6cacfa251afbef04f048472c2 (patch)
tree57b42e9f6699bdb7609c47d8707f271bea4df80e
parent3555fdce0c9cf9bb6860a79fdc6843a1e96c9888 (diff)
downloadyahns-2c5b5bb7a3bab2d6cacfa251afbef04f048472c2.tar.gz
We want to shutdown gracefully, but still relatively quickly (to
make way for the new one).  So we must disable persistent
connections to prevent clients from keeping to-be-dead server alive
indefinitely.
-rw-r--r--lib/yahns/config.rb4
-rw-r--r--lib/yahns/server.rb14
-rw-r--r--lib/yahns/server_mp.rb9
-rw-r--r--test/test_server.rb10
4 files changed, 25 insertions, 12 deletions
diff --git a/lib/yahns/config.rb b/lib/yahns/config.rb
index d38c090..4861f3e 100644
--- a/lib/yahns/config.rb
+++ b/lib/yahns/config.rb
@@ -29,6 +29,10 @@ class Yahns::Config # :nodoc:
     raise ArgumentError, msg
   end
 
+  def postfork_cleanup
+    @app_ctx = @set = @qeggs = @app_instances = @config_file = nil
+  end
+
   def config_reload! #:nodoc:
     # app_instance:app_ctx is a 1:N relationship
     @config_listeners = {} # name/address -> options
diff --git a/lib/yahns/server.rb b/lib/yahns/server.rb
index c7a5a57..e8f1213 100644
--- a/lib/yahns/server.rb
+++ b/lib/yahns/server.rb
@@ -292,14 +292,22 @@ class Yahns::Server # :nodoc:
     @logger.info "#{prefix}done reopening logs"
   end
 
+  def quit_enter(alive)
+    self.listeners = []
+    exit(0) unless alive # drop connections immediately if signaled twice
+    @config.config_listeners.each_value do |opts|
+      ctx = opts[:yahns_app_ctx] or next
+      ctx.persistent_connections = false # Yahns::HttpContext
+    end
+    false
+  end
+
   def sp_sig_handle(alive)
     @sev.kgio_wait_readable(alive ? nil : 0.01)
     @sev.yahns_step
     case sig = @sig_queue.shift
     when :QUIT, :TERM, :INT
-      self.listeners = [] # stop accepting new connections
-      exit(0) unless alive
-      return false
+      return quit_enter(alive)
     when :USR1
       usr1_reopen('')
     when :USR2
diff --git a/lib/yahns/server_mp.rb b/lib/yahns/server_mp.rb
index 8818bac..c75a3c9 100644
--- a/lib/yahns/server_mp.rb
+++ b/lib/yahns/server_mp.rb
@@ -151,7 +151,7 @@ module Yahns::ServerMP # :nodoc:
   def fdmap_init_mp
     fdmap = fdmap_init # builds apps (if not preloading)
     EXIT_SIGS.each { |sig| trap(sig) { sqwakeup(sig) } }
-    @config = nil
+    @config.postfork_cleanup # reduce live objects
     fdmap
   end
 
@@ -170,12 +170,9 @@ module Yahns::ServerMP # :nodoc:
     # not performance critical
     r = IO.select([worker, @sev], nil, nil, alive ? nil : 0.01) and
       r[0].each { |io| io.yahns_step }
-    case sig = @sig_queue.shift
+    case @sig_queue.shift
     when *EXIT_SIGS
-      self.listeners = []
-      exit(0) unless alive # drop connections immediately if signaled twice
-      @logger.info("received SIG#{sig}, gracefully exiting")
-      return false
+      return quit_enter(alive)
     when :USR1
       usr1_reopen("worker ")
     end
diff --git a/test/test_server.rb b/test/test_server.rb
index 289770d..88dd3fb 100644
--- a/test/test_server.rb
+++ b/test/test_server.rb
@@ -50,12 +50,16 @@ class TestServer < Testcase
         buf << c.readpartial(4096)
       end
     end
+    Process.kill(:QUIT, pid)
+    "GET / HTTP/1.1\r\n\r\n".each_byte { |x| Thread.pass; c.write(x.chr) }
+    buf = Timeout.timeout(10) { c.read }
+    assert_match(/Connection: close/, buf)
+    _, status = Timeout.timeout(10) { Process.waitpid2(pid) }
+    assert status.success?, status.inspect
+    c.close
   rescue => e
     Yahns::Log.exception(Logger.new($stderr), "test", e)
     raise
-  ensure
-    c.close if c
-    quit_wait(pid)
   end
 
   def test_input_body_true; input_body(true); end