Skip to content

Commit 2eef470

Browse files
authored
Merge branch 'master' into test_against_unstable_hiredis-py
2 parents 9b73426 + 120517f commit 2eef470

30 files changed

+717
-339
lines changed

.github/workflows/integration.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ jobs:
7474
max-parallel: 15
7575
fail-fast: false
7676
matrix:
77-
redis-version: ['8.0-RC1-pre', '${{ needs.redis_version.outputs.CURRENT }}', '7.2.7', '6.2.17']
77+
redis-version: ['8.0-RC2-pre', '${{ needs.redis_version.outputs.CURRENT }}', '7.2.7', '6.2.17']
7878
python-version: ['3.8', '3.13']
7979
parser-backend: ['plain']
8080
event-loop: ['asyncio']

docker-compose.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
x-client-libs-stack-image: &client-libs-stack-image
3-
image: "redislabs/client-libs-test:${CLIENT_LIBS_TEST_STACK_IMAGE_TAG:-7.4.2}"
3+
image: "redislabs/client-libs-test:${CLIENT_LIBS_TEST_STACK_IMAGE_TAG:-rs-7.4.0-v2}"
44

55
x-client-libs-image: &client-libs-image
66
image: "redislabs/client-libs-test:${CLIENT_LIBS_TEST_IMAGE_TAG:-7.4.2}"

docs/clustering.rst

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -187,8 +187,8 @@ When a ClusterPubSub instance is created without specifying a node, a
187187
single node will be transparently chosen for the pubsub connection on
188188
the first command execution. The node will be determined by: 1. Hashing
189189
the channel name in the request to find its keyslot 2. Selecting a node
190-
that handles the keyslot: If read_from_replicas is set to true, a
191-
replica can be selected.
190+
that handles the keyslot: If read_from_replicas is set to true or
191+
load_balancing_strategy is provided, a replica can be selected.
192192
193193
Known PubSub Limitations
194194
------------------------
@@ -216,9 +216,12 @@ By default, Redis Cluster always returns MOVE redirection response on
216216
accessing a replica node. You can overcome this limitation and scale
217217
read commands by triggering READONLY mode.
218218
219-
To enable READONLY mode pass read_from_replicas=True to RedisCluster
220-
constructor. When set to true, read commands will be assigned between
219+
To enable READONLY mode pass read_from_replicas=True or define
220+
a load_balancing_strategy to RedisCluster constructor.
221+
When read_from_replicas is set to true read commands will be assigned between
221222
the primary and its replications in a Round-Robin manner.
223+
With load_balancing_strategy you can define a custom strategy for
224+
assigning read commands to the replicas and primary nodes.
222225
223226
READONLY mode can be set at runtime by calling the readonly() method
224227
with target_nodes=‘replicas’, and read-write access can be restored by

docs/examples/ssl_connection_examples.ipynb

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,10 @@
3434
"import redis\n",
3535
"\n",
3636
"r = redis.Redis(\n",
37-
" host='localhost', \n",
38-
" port=6666, \n",
39-
" ssl=True, \n",
37+
" host='localhost',\n",
38+
" port=6666,\n",
39+
" ssl=True,\n",
40+
" ssl_check_hostname=False,\n",
4041
" ssl_cert_reqs=\"none\",\n",
4142
")\n",
4243
"r.ping()"
@@ -68,7 +69,7 @@
6869
"source": [
6970
"import redis\n",
7071
"\n",
71-
"r = redis.from_url(\"rediss://localhost:6666?ssl_cert_reqs=none&decode_responses=True&health_check_interval=2\")\n",
72+
"r = redis.from_url(\"rediss://localhost:6666?ssl_cert_reqs=none&ssl_check_hostname=False&decode_responses=True&health_check_interval=2\")\n",
7273
"r.ping()"
7374
]
7475
},
@@ -99,13 +100,14 @@
99100
"import redis\n",
100101
"\n",
101102
"redis_pool = redis.ConnectionPool(\n",
102-
" host=\"localhost\", \n",
103-
" port=6666, \n",
104-
" connection_class=redis.SSLConnection, \n",
103+
" host=\"localhost\",\n",
104+
" port=6666,\n",
105+
" connection_class=redis.SSLConnection,\n",
106+
" ssl_check_hostname=False,\n",
105107
" ssl_cert_reqs=\"none\",\n",
106108
")\n",
107109
"\n",
108-
"r = redis.StrictRedis(connection_pool=redis_pool) \n",
110+
"r = redis.StrictRedis(connection_pool=redis_pool)\n",
109111
"r.ping()"
110112
]
111113
},
@@ -141,6 +143,7 @@
141143
" port=6666,\n",
142144
" ssl=True,\n",
143145
" ssl_min_version=ssl.TLSVersion.TLSv1_3,\n",
146+
" ssl_check_hostname=False,\n",
144147
" ssl_cert_reqs=\"none\",\n",
145148
")\n",
146149
"r.ping()"

docs/retry.rst

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,25 +13,25 @@ Retry in Redis Standalone
1313
>>> from redis.client import Redis
1414
>>> from redis.exceptions import (
1515
>>> BusyLoadingError,
16-
>>> ConnectionError,
17-
>>> TimeoutError
16+
>>> RedisError,
1817
>>> )
1918
>>>
2019
>>> # Run 3 retries with exponential backoff strategy
2120
>>> 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)
21+
>>> # Redis client with retries on custom errors in addition to the errors
22+
>>> # that are already retried by default
23+
>>> r = Redis(host='localhost', port=6379, retry=retry, retry_on_error=[BusyLoadingError, RedisError])
2624

27-
As you can see from the example above, Redis client supports 3 parameters to configure the retry behaviour:
25+
As you can see from the example above, Redis client supports 2 parameters to configure the retry behaviour:
2826

2927
* ``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
28+
* The :class:`~.Retry` instance has default set of :ref:`exceptions-label` to retry on,
29+
which can be overridden by passing a tuple with :ref:`exceptions-label` to the ``supported_errors`` parameter.
30+
* ``retry_on_error``: list of additional :ref:`exceptions-label` to retry on
3231

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).
32+
33+
If no ``retry`` is provided, a default one is created with :class:`~.ExponentialWithJitterBackoff` as backoff strategy
34+
and 3 retries.
3535

3636

3737
Retry in Redis Cluster
@@ -44,27 +44,30 @@ Retry in Redis Cluster
4444
>>> # Run 3 retries with exponential backoff strategy
4545
>>> retry = Retry(ExponentialBackoff(), 3)
4646
>>> # Redis Cluster client with retries
47-
>>> rc = RedisCluster(host='localhost', port=6379, retry=retry, cluster_error_retry_attempts=2)
47+
>>> rc = RedisCluster(host='localhost', port=6379, retry=retry)
4848

4949
Retry behaviour in Redis Cluster is a little bit different from Standalone:
5050

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``
51+
* ``retry``: :class:`~.Retry` instance with a :ref:`backoff-label` strategy and the max number of retries, default value is ``Retry(ExponentialWithJitterBackoff(base=1, cap=10), cluster_error_retry_attempts)``
52+
* ``cluster_error_retry_attempts``: number of times to retry before raising an error when :class:`~.TimeoutError`, :class:`~.ConnectionError`, :class:`~.ClusterDownError` or :class:`~.SlotNotCoveredError` are encountered, default value is ``3``
53+
* This argument is deprecated - it is used to initialize the number of retries for the retry object,
54+
only in the case when the ``retry`` object is not provided.
55+
When the ``retry`` argument is provided, the ``cluster_error_retry_attempts`` argument is ignored!
56+
57+
* The retry object is not yet fully utilized in the cluster client.
58+
The retry object is used only to determine the number of retries for the cluster level calls.
5359

5460
Let's consider the following example:
5561

5662
>>> from redis.backoff import ExponentialBackoff
5763
>>> from redis.retry import Retry
5864
>>> from redis.cluster import RedisCluster
5965
>>>
60-
>>> rc = RedisCluster(host='localhost', port=6379, retry=Retry(ExponentialBackoff(), 6), cluster_error_retry_attempts=1)
66+
>>> rc = RedisCluster(host='localhost', port=6379, retry=Retry(ExponentialBackoff(), 6))
6167
>>> rc.set('foo', 'bar')
6268

6369
#. the client library calculates the hash slot for key 'foo'.
6470
#. given the hash slot, it then determines which node to connect to, in order to execute the command.
6571
#. 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.
72+
#. because we set ``retry=Retry(ExponentialBackoff(), 6)``, the cluster client starts a cluster update, removes the failed node from the startup nodes, and re-initializes the cluster.
73+
#. the cluster client retries the command until it either succeeds or the max number of retries is reached.

0 commit comments

Comments
 (0)