Skip to content

Commit

Permalink
Treat ReadOnlyError as a ConnectionError
Browse files Browse the repository at this point in the history
Fix: #1168
  • Loading branch information
tylerbrewer2 authored and byroot committed Nov 23, 2022
1 parent a8e00cb commit 3c42db6
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 3 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Unreleased

- Treat ReadOnlyError as ConnectionError. See #1168.

# 5.0.5

- Fix automatic disconnection when the process was forked. See #1157.
Expand Down
7 changes: 4 additions & 3 deletions lib/redis/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,6 @@ class PermissionError < CommandError
class WrongTypeError < CommandError
end

class ReadOnlyError < CommandError
end

class OutOfMemoryError < CommandError
end

Expand All @@ -52,6 +49,10 @@ class TimeoutError < BaseConnectionError
class InheritedError < BaseConnectionError
end

# Generally raised during Redis failover scenarios
class ReadOnlyError < BaseConnectionError
end

# Raised when client options are invalid.
class InvalidClientOptionError < BaseError
end
Expand Down
34 changes: 34 additions & 0 deletions test/redis/internals_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -291,4 +291,38 @@ def test_can_be_duped_to_create_a_new_connection

assert_equal clients + 1, r.info["connected_clients"].to_i
end

def test_reconnect_on_readonly_errors
tcp_server = TCPServer.new("127.0.0.1", 0)
tcp_server.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true)
port = tcp_server.addr[1]

server_thread = Thread.new do
session = tcp_server.accept
io = RedisClient::RubyConnection::BufferedIO.new(session, read_timeout: 1, write_timeout: 1)
2.times do
command = RedisClient::RESP3.load(io)
case command.first.upcase
when "PING"
session.write("+PONG\r\n")
when "SET"
session.write("-READONLY You can't write against a read only replica.\r\n")
else
session.write("-ERR Unknown command #{command.first}\r\n")
end
end
session.close
end

redis = Redis.new(host: "127.0.0.1", port: port, timeout: 2, reconnect_attempts: 0)
assert_equal "PONG", redis.ping

assert_raises Redis::ReadOnlyError do
redis.set("foo", "bar")
end

refute_predicate redis, :connected?
ensure
server_thread&.kill
end
end

0 comments on commit 3c42db6

Please sign in to comment.