Skip to content

Commit 3c42db6

Browse files
tylerbrewer2byroot
authored andcommitted
Treat ReadOnlyError as a ConnectionError
Fix: #1168
1 parent a8e00cb commit 3c42db6

File tree

3 files changed

+40
-3
lines changed

3 files changed

+40
-3
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Unreleased
22

3+
- Treat ReadOnlyError as ConnectionError. See #1168.
4+
35
# 5.0.5
46

57
- Fix automatic disconnection when the process was forked. See #1157.

lib/redis/errors.rb

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,6 @@ class PermissionError < CommandError
2626
class WrongTypeError < CommandError
2727
end
2828

29-
class ReadOnlyError < CommandError
30-
end
31-
3229
class OutOfMemoryError < CommandError
3330
end
3431

@@ -52,6 +49,10 @@ class TimeoutError < BaseConnectionError
5249
class InheritedError < BaseConnectionError
5350
end
5451

52+
# Generally raised during Redis failover scenarios
53+
class ReadOnlyError < BaseConnectionError
54+
end
55+
5556
# Raised when client options are invalid.
5657
class InvalidClientOptionError < BaseError
5758
end

test/redis/internals_test.rb

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,4 +291,38 @@ def test_can_be_duped_to_create_a_new_connection
291291

292292
assert_equal clients + 1, r.info["connected_clients"].to_i
293293
end
294+
295+
def test_reconnect_on_readonly_errors
296+
tcp_server = TCPServer.new("127.0.0.1", 0)
297+
tcp_server.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true)
298+
port = tcp_server.addr[1]
299+
300+
server_thread = Thread.new do
301+
session = tcp_server.accept
302+
io = RedisClient::RubyConnection::BufferedIO.new(session, read_timeout: 1, write_timeout: 1)
303+
2.times do
304+
command = RedisClient::RESP3.load(io)
305+
case command.first.upcase
306+
when "PING"
307+
session.write("+PONG\r\n")
308+
when "SET"
309+
session.write("-READONLY You can't write against a read only replica.\r\n")
310+
else
311+
session.write("-ERR Unknown command #{command.first}\r\n")
312+
end
313+
end
314+
session.close
315+
end
316+
317+
redis = Redis.new(host: "127.0.0.1", port: port, timeout: 2, reconnect_attempts: 0)
318+
assert_equal "PONG", redis.ping
319+
320+
assert_raises Redis::ReadOnlyError do
321+
redis.set("foo", "bar")
322+
end
323+
324+
refute_predicate redis, :connected?
325+
ensure
326+
server_thread&.kill
327+
end
294328
end

0 commit comments

Comments
 (0)