diff --git a/History.md b/History.md index 991d7186ce..28570e64fd 100644 --- a/History.md +++ b/History.md @@ -33,6 +33,7 @@ * Log binding on http:// for TCP bindings to make it clickable * Bugfixes + * Improve shutdown reliability (#2312) * Close client http connections made to an ssl server with TLSv1.3 (#2116) * Do not set user_config to quiet by default to allow for file config (#2074) * Always close SSL connection in Puma::ControlCLI (#2211) diff --git a/lib/puma/events.rb b/lib/puma/events.rb index 8c2323f73b..c746c9d1a5 100644 --- a/lib/puma/events.rb +++ b/lib/puma/events.rb @@ -65,7 +65,8 @@ def register(hook, obj=nil, &blk) # Write +str+ to +@stdout+ # def log(str) - @stdout.puts format(str) + @stdout.puts format(str) if @stdout.respond_to? :puts + rescue Errno::EPIPE end def write(str) diff --git a/lib/puma/server.rb b/lib/puma/server.rb index 0ef5aa55dc..2ba99f5243 100644 --- a/lib/puma/server.rb +++ b/lib/puma/server.rb @@ -317,7 +317,12 @@ def handle_servers rescue Exception => e @events.unknown_error e, nil, "Exception handling servers" ensure - @check.close unless @check.closed? # Ruby 2.2 issue + begin + @check.close unless @check.closed? + rescue Errno::EBADF, RuntimeError + # RuntimeError is Ruby 2.2 issue, can't modify frozen IOError + # Errno::EBADF is infrequently raised + end @notify.close @notify = nil @check = nil @@ -912,7 +917,7 @@ def notify_safely(message) @check, @notify = Puma::Util.pipe unless @notify begin @notify << message - rescue IOError + rescue IOError, NoMethodError, Errno::EPIPE # The server, in another thread, is shutting down Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue rescue RuntimeError => e diff --git a/test/helper.rb b/test/helper.rb index 472407076d..fa5cd20ca3 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -58,8 +58,11 @@ module TimeoutEveryTestCase class TestTookTooLong < Timeout::Error end - def capture_exceptions(*) - ::Timeout.timeout(RUBY_ENGINE == 'ruby' ? 60 : 120, TestTookTooLong) { super } + def time_it + t0 = Minitest.clock_time + ::Timeout.timeout(RUBY_ENGINE == 'ruby' ? 60 : 120, TestTookTooLong) { yield } + ensure + self.time = Minitest.clock_time - t0 end end diff --git a/test/test_integration_cluster.rb b/test/test_integration_cluster.rb index 524cd4ae6c..f409443c79 100644 --- a/test/test_integration_cluster.rb +++ b/test/test_integration_cluster.rb @@ -387,7 +387,7 @@ def bad_exit_pids(pids) # used with thread_run to define correct 'refused' errors def thread_run_refused(unix: false) if unix - DARWIN ? [Errno::ENOENT, IOError] : [Errno::ENOENT] + [Errno::ENOENT, IOError] else DARWIN ? [Errno::ECONNREFUSED, Errno::EPIPE, EOFError] : [Errno::ECONNREFUSED]