Skip to content

Commit af44021

Browse files
Retry documentation. (#2166) (#2456)
* Retry documentation. (#2166) * Fixed typo. * Update docs/retry.rst Co-authored-by: Nermina Miller <[email protected]> * Update docs/retry.rst Co-authored-by: Nermina Miller <[email protected]> * Update docs/retry.rst Co-authored-by: Nermina Miller <[email protected]> * Update docs/retry.rst Co-authored-by: Nermina Miller <[email protected]> * Update docs/retry.rst Co-authored-by: Nermina Miller <[email protected]> * Update docs/retry.rst Co-authored-by: Nermina Miller <[email protected]> * Update docs/retry.rst Co-authored-by: Nermina Miller <[email protected]> * Update docs/retry.rst Co-authored-by: Nermina Miller <[email protected]> Co-authored-by: Nermina Miller <[email protected]>
1 parent fa45fb1 commit af44021

File tree

3 files changed

+69
-2
lines changed

3 files changed

+69
-2
lines changed

docs/backoff.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
.. _backoff-label:
2+
13
Backoff
24
#############
35

docs/exceptions.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
1+
.. _exceptions-label:
22

33
Exceptions
44
##########

docs/retry.rst

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,69 @@ Retry Helpers
22
#############
33

44
.. automodule:: redis.retry
5-
:members:
5+
:members:
6+
7+
8+
Retry in Redis Standalone
9+
**************************
10+
11+
>>> from redis.backoff import ExponentialBackoff
12+
>>> from redis.retry import Retry
13+
>>> from redis.client import Redis
14+
>>> from redis.exceptions import (
15+
>>> BusyLoadingError,
16+
>>> ConnectionError,
17+
>>> TimeoutError
18+
>>> )
19+
>>>
20+
>>> # Run 3 retries with exponential backoff strategy
21+
>>> retry = Retry(ExponentialBackoff(), 3)
22+
>>> # Redis client with retries on custom errors
23+
>>> r = Redis(host='localhost', port=6379, retry=retry, retry_on_error=[BusyLoadingError, ConnectionError, TimeoutError])
24+
>>> # Redis client with retries on TimeoutError only
25+
>>> r_only_timeout = Redis(host='localhost', port=6379, retry=retry, retry_on_timeout=True)
26+
27+
As you can see from the example above, Redis client supports 3 parameters to configure the retry behaviour:
28+
29+
* ``retry``: :class:`~.Retry` instance with a :ref:`backoff-label` strategy and the max number of retries
30+
* ``retry_on_error``: list of :ref:`exceptions-label` to retry on
31+
* ``retry_on_timeout``: if ``True``, retry on :class:`~.TimeoutError` only
32+
33+
If either ``retry_on_error`` or ``retry_on_timeout`` are passed and no ``retry`` is given,
34+
by default it uses a ``Retry(NoBackoff(), 1)`` (meaning 1 retry right after the first failure).
35+
36+
37+
Retry in Redis Cluster
38+
**************************
39+
40+
>>> from redis.backoff import ExponentialBackoff
41+
>>> from redis.retry import Retry
42+
>>> from redis.cluster import RedisCluster
43+
>>>
44+
>>> # Run 3 retries with exponential backoff strategy
45+
>>> retry = Retry(ExponentialBackoff(), 3)
46+
>>> # Redis Cluster client with retries
47+
>>> rc = RedisCluster(host='localhost', port=6379, retry=retry, cluster_error_retry_attempts=2)
48+
49+
Retry behaviour in Redis Cluster is a little bit different from Standalone:
50+
51+
* ``retry``: :class:`~.Retry` instance with a :ref:`backoff-label` strategy and the max number of retries, default value is ``Retry(NoBackoff(), 0)``
52+
* ``cluster_error_retry_attempts``: number of times to retry before raising an error when :class:`~.TimeoutError` or :class:`~.ConnectionError` or :class:`~.ClusterDownError` are encountered, default value is ``3``
53+
54+
Let's consider the following example:
55+
56+
>>> from redis.backoff import ExponentialBackoff
57+
>>> from redis.retry import Retry
58+
>>> from redis.cluster import RedisCluster
59+
>>>
60+
>>> rc = RedisCluster(host='localhost', port=6379, retry=Retry(ExponentialBackoff(), 6), cluster_error_retry_attempts=1)
61+
>>> rc.set('foo', 'bar')
62+
63+
#. the client library calculates the hash slot for key 'foo'.
64+
#. given the hash slot, it then determines which node to connect to, in order to execute the command.
65+
#. during the connection, a :class:`~.ConnectionError` is raised.
66+
#. because we set ``retry=Retry(ExponentialBackoff(), 6)``, the client tries to reconnect to the node up to 6 times, with an exponential backoff between each attempt.
67+
#. even after 6 retries, the client is still unable to connect.
68+
#. because we set ``cluster_error_retry_attempts=1``, before giving up, the client starts a cluster update, removes the failed node from the startup nodes, and re-initializes the cluster.
69+
#. after the cluster has been re-initialized, it starts a new cycle of retries, up to 6 retries, with an exponential backoff.
70+
#. if the client can connect, we're good. Otherwise, the exception is finally raised to the caller, because we've run out of attempts.

0 commit comments

Comments
 (0)