Description
Version: 4.5.5
Platform: Python 3.10.10, Ubuntu 22.04
Description:
When the Redis
client is initialized with retry_on_timeout
set to True
or retry_on_error
set to [redis.exceptions.TimeoutError, socket.timeout]
and connection_pool
is not provided, the timeout retrying does not work in client's pipeline execution.
For example:
my_redis_client = redis.StrictRedis(
host='...',
port=6380,
password='...',
ssl=True,
socket_timeout=30,
socket_connect_timeout=30,
retry=retry,
retry_on_timeout=True,
)
pipe = my_redis_client.pipeline()
pipe.incr(name='key')
pipe.execute() # Retrying on timeout won't work here
Problem found:
Inside Redis
init method only retry_on_error
is propagated through newly created kwargs
into the created ConnectionPool
(line 1043 in redis/client.py
) with retry_on_timeout
causing TimeoutError
to be added to retry_on_error
(line 988 in redis/client.py
).
Subsequently, when a Redis Pipeline is initialized from the client using the pipeline
method (1096 in redis/client.py
), it is initialized using the ConnectionPool
created in the Redis
constructor.
When we execute the pipeline using the execute
method (line 2100 in redis/client.py
), conn.retry.call_with_retry
will be called, where conn
is a Connection
object initiated from the ConnectionPool
with retry_on_error
set, and retry_on_timeout
not set as it was not propagated into ConnectionPool
and thus to Connection
.
When a timeout occurs while executing the pipeline, _disconnect_raise_reset(conn, error)
method of the Redis Pipeline is called (line 2080
in redis/client.py
). The problem with this method is that it will always re-raise the TimeoutError
due to conn.retry_on_timeout
always being False
. The reason is that conn
was created from the ConnectionPool
, which was initialized without retry_on_timeout
being set (in the Redis
constructor).
Possible fix:
Use retry_on_error
instead of retry_on_timeout
inside _disconnect_raise_reset
.