-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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_timeoutalways 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.