Skip to content

Commit

Permalink
temporary workaround for https://bugs.ruby-lang.org/issues/13632 (#1345)
Browse files Browse the repository at this point in the history
* temporary workaround for https://bugs.ruby-lang.org/issues/13632
Purging interrupt queue if IOError was caught.

* fixing only if mri

* optimization to avoid redundant checks in empty queue

* scoping fix to only affected versions

* serving ruby version from mkmf

* safe invoking for the workaround

* switching to preprocessor vars

* purging queue on runtime error

* rubocop fix

* covering workaround

* improving names

* styling

* rubocop fixes

* improved test reporting

* wording

* condition

* improving comment

* bugfix moved to separate gem: https://rubygems.org/gems/stopgap_13632

* using stopgap_13632 in gemfile to fix the builds

* requiring stopgap for tests
  • Loading branch information
NikolayRys authored and nateberkopec committed Jul 19, 2017
1 parent 31b0282 commit 9141613
Show file tree
Hide file tree
Showing 7 changed files with 26 additions and 4 deletions.
4 changes: 4 additions & 0 deletions Gemfile
Expand Up @@ -14,3 +14,7 @@ gem "minitest", "~> 5.9"
gem "jruby-openssl", :platform => "jruby"

gem "rubocop", "~> 0.49.1"

if %w(2.2.7 2.3.4 2.4.1).include? RUBY_VERSION
gem "stopgap_13632", "~> 1.0", :platform => "mri"
end
1 change: 1 addition & 0 deletions lib/puma/client.rb
Expand Up @@ -111,6 +111,7 @@ def close
begin
@io.close
rescue IOError
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
end
end

Expand Down
3 changes: 3 additions & 0 deletions lib/puma/cluster.rb
Expand Up @@ -224,6 +224,7 @@ def wakeup!
begin
@wakeup.write "!" unless @wakeup.closed?
rescue SystemCallError, IOError
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
end
end

Expand Down Expand Up @@ -267,6 +268,7 @@ def worker(index, master)
begin
@worker_write << "b#{Process.pid}\n"
rescue SystemCallError, IOError
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
STDERR.puts "Master seems to have exited, exiting."
return
end
Expand All @@ -282,6 +284,7 @@ def worker(index, master)
payload = %Q!#{base_payload}{ "backlog":#{b}, "running":#{r} }\n!
io << payload
rescue IOError
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
break
end
end
Expand Down
1 change: 1 addition & 0 deletions lib/puma/minissl.rb
Expand Up @@ -118,6 +118,7 @@ def close
return if read_and_drop(1) == :timeout
end
rescue IOError, SystemCallError
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
# nothing
ensure
@socket.close
Expand Down
3 changes: 3 additions & 0 deletions lib/puma/reactor.rb
Expand Up @@ -28,6 +28,7 @@ def run_internal
begin
ready = IO.select sockets, nil, nil, @sleep_for
rescue IOError => e
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
if sockets.any? { |socket| socket.closed? }
STDERR.puts "Error in select: #{e.message} (#{e.class})"
STDERR.puts e.backtrace
Expand Down Expand Up @@ -195,13 +196,15 @@ def clear!
begin
@trigger << "c"
rescue IOError
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
end
end

def shutdown
begin
@trigger << "!"
rescue IOError
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
end

@thread.join
Expand Down
16 changes: 12 additions & 4 deletions lib/puma/server.rb
Expand Up @@ -110,13 +110,15 @@ def cork_socket(socket)
begin
socket.setsockopt(6, 3, 1) if socket.kind_of? TCPSocket
rescue IOError, SystemCallError
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
end
end

def uncork_socket(socket)
begin
socket.setsockopt(6, 3, 0) if socket.kind_of? TCPSocket
rescue IOError, SystemCallError
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
end
end

Expand All @@ -127,6 +129,7 @@ def closed_socket?(socket)
begin
tcp_info = socket.getsockopt(Socket::SOL_TCP, Socket::TCP_INFO)
rescue IOError, SystemCallError
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
@precheck_closing = false
false
else
Expand Down Expand Up @@ -490,6 +493,7 @@ def process_client(client, buffer)
begin
client.close if close_socket
rescue IOError, SystemCallError
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
# Already closed
rescue StandardError => e
@events.unknown_error self, e, "Client"
Expand Down Expand Up @@ -896,11 +900,15 @@ def notify_safely(message)
begin
@notify << message
rescue IOError
# The server, in another thread, is shutting down
# The server, in another thread, is shutting down
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
rescue RuntimeError => e
# The server, in another thread, has been shut down during the system call
# https://github.com/puma/puma/pull/1206
raise e unless e.message.include?('IOError')
# Temporary workaround for https://bugs.ruby-lang.org/issues/13239
if e.message.include?('IOError')
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
else
raise e
end
end
end
private :notify_safely
Expand Down
2 changes: 2 additions & 0 deletions test/helper.rb
@@ -1,6 +1,8 @@
# Copyright (c) 2011 Evan Phoenix
# Copyright (c) 2005 Zed A. Shaw

require 'stopgap_13632' if %w(2.2.7 2.3.4 2.4.1).include? RUBY_VERSION

begin
require "bundler/setup"
rescue LoadError
Expand Down

0 comments on commit 9141613

Please sign in to comment.