Skip to content

Commit

Permalink
Improve redis-client error translation
Browse files Browse the repository at this point in the history
Automatically handle subclasses, useful for CommandError for instance.
  • Loading branch information
byroot committed Sep 5, 2022
1 parent d180452 commit 5824da1
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 5 deletions.
3 changes: 3 additions & 0 deletions .rubocop.yml
Expand Up @@ -68,6 +68,9 @@ Style/NumericPredicate:
Style/IfUnlessModifier:
Enabled: false

Style/MutableConstant:
Enabled: false # false positives

Style/SignalException:
Exclude:
- 'lib/redis/connection/synchrony.rb'
Expand Down
25 changes: 20 additions & 5 deletions lib/redis/client.rb
Expand Up @@ -15,7 +15,7 @@ class Client < ::RedisClient
RedisClient::WrongTypeError => Redis::WrongTypeError,
RedisClient::ReadOnlyError => Redis::ReadOnlyError,
RedisClient::ProtocolError => Redis::ProtocolError,
}.freeze
}

class << self
def config(**kwargs)
Expand Down Expand Up @@ -78,7 +78,7 @@ def password
def call_v(command, &block)
super(command, &block)
rescue ::RedisClient::Error => error
raise ERROR_MAPPING.fetch(error.class), error.message, error.backtrace
translate_error!(error)
end

def blocking_call_v(timeout, command, &block)
Expand All @@ -91,19 +91,19 @@ def blocking_call_v(timeout, command, &block)

super(timeout, command, &block)
rescue ::RedisClient::Error => error
raise ERROR_MAPPING.fetch(error.class), error.message, error.backtrace
translate_error!(error)
end

def pipelined
super
rescue ::RedisClient::Error => error
raise ERROR_MAPPING.fetch(error.class), error.message, error.backtrace
translate_error!(error)
end

def multi
super
rescue ::RedisClient::Error => error
raise ERROR_MAPPING.fetch(error.class), error.message, error.backtrace
translate_error!(error)
end

def disable_reconnection(&block)
Expand All @@ -121,6 +121,21 @@ def close

private

def translate_error!(error)
redis_error = translate_error_class(error.class)
raise redis_error, error.message, error.backtrace
end

def translate_error_class(error_class)
ERROR_MAPPING.fetch(error_class)
rescue IndexError
if (client_error = error_class.ancestors.find { |a| ERROR_MAPPING[a] })
ERROR_MAPPING[error_class] = ERROR_MAPPING[client_error]
else
raise
end
end

def ensure_connected(retryable: true)
unless @inherit_socket || (@pid ||= Process.pid) == Process.pid
raise InheritedError,
Expand Down
9 changes: 9 additions & 0 deletions test/redis/client_test.rb
Expand Up @@ -26,6 +26,15 @@ def test_call_raise
end
end

def test_error_translate_subclasses
error = Class.new(RedisClient::CommandError)
assert_equal Redis::CommandError, r._client.send(:translate_error_class, error.new)

assert_raises KeyError do
r._client.send(:translate_error_class, StandardError.new)
end
end

def test_mixed_encoding
r.call("MSET", "fée", "\x00\xFF".b, "じ案".encode(Encoding::SHIFT_JIS), "\t".encode(Encoding::ASCII))
assert_equal "\x00\xFF".b, r.call("GET", "fée")
Expand Down

0 comments on commit 5824da1

Please sign in to comment.