Skip to content

Commit

Permalink
rescue IO::TimeoutError raised by Ruby since 3.2.0 on blocking reads/…
Browse files Browse the repository at this point in the history
…writes

One scenario in which this happens is when a firewall silently drops
connections between clients and memcached instances.

With this patch the client reopens the connection and the request succeeds.
Without it, IO:TimeoutError is raised for the application to handle which
deviates from Dalli behavior under Ruby 3.1 and earlier.
  • Loading branch information
skaes committed Sep 25, 2023
1 parent d61dbcc commit 4acae51
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 4 deletions.
9 changes: 9 additions & 0 deletions lib/dalli/protocol.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,14 @@ module Dalli
module Protocol
# Preserved for backwards compatibility. Should be removed in 4.0
NOT_FOUND = ::Dalli::NOT_FOUND

# Ruby 3.2 raises IO::TimeoutError on blocking reads/writes, but
# it is not defined in earlier Ruby versions.
require 'timeout'
if defined?(IO::TimeoutError)
TIMEOUT_ERRORS = [Timeout::Error, IO::TimeoutError]
else
TIMEOUT_ERRORS = [Timeout::Error]
end
end
end
2 changes: 1 addition & 1 deletion lib/dalli/protocol/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def pipeline_next_responses
end

values
rescue SystemCallError, Timeout::Error, EOFError => e
rescue SystemCallError, *TIMEOUT_ERRORS, EOFError => e
@connection_manager.error_on_request!(e)
end

Expand Down
6 changes: 3 additions & 3 deletions lib/dalli/protocol/connection_manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -150,19 +150,19 @@ def read_line
data = @sock.gets("\r\n")
error_on_request!('EOF in read_line') if data.nil?
data
rescue SystemCallError, Timeout::Error, EOFError => e
rescue SystemCallError, *TIMEOUT_ERRORS, EOFError => e
error_on_request!(e)
end

def read(count)
@sock.readfull(count)
rescue SystemCallError, Timeout::Error, EOFError => e
rescue SystemCallError, *TIMEOUT_ERRORS, EOFError => e
error_on_request!(e)
end

def write(bytes)
@sock.write(bytes)
rescue SystemCallError, Timeout::Error => e
rescue SystemCallError, *TIMEOUT_ERRORS => e
error_on_request!(e)
end

Expand Down

0 comments on commit 4acae51

Please sign in to comment.