Skip to content

Commit fb6379a

Browse files
authored
Python- Add Batch Option Classes for exec (valkey-io#4027)
1 parent dfbc991 commit fb6379a

File tree

7 files changed

+391
-106
lines changed

7 files changed

+391
-106
lines changed

python/python/glide/__init__.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@
77
TBatch,
88
Transaction,
99
)
10+
from glide.async_commands.batch_options import (
11+
BatchOptions,
12+
BatchRetryStrategy,
13+
ClusterBatchOptions,
14+
)
1015
from glide.async_commands.bitmap import (
1116
BitEncoding,
1217
BitFieldGet,
@@ -189,6 +194,10 @@
189194
"Transaction",
190195
"TGlideClient",
191196
"TBatch",
197+
# Batch Options
198+
"BatchOptions",
199+
"BatchRetryStrategy",
200+
"ClusterBatchOptions",
192201
# Config
193202
"AdvancedGlideClientConfiguration",
194203
"AdvancedGlideClusterClientConfiguration",
Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
# Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0
2+
3+
from typing import Optional
4+
5+
from glide.constants import TSingleNodeRoute
6+
7+
8+
class BatchRetryStrategy:
9+
"""
10+
Defines a retry strategy for cluster batch requests, allowing control over retries in case of
11+
server or connection errors.
12+
13+
This strategy determines whether failed commands should be retried, impacting execution order
14+
and potential side effects.
15+
16+
Behavior:
17+
- If `retry_server_error` is `True`, failed commands with a retriable error (e.g.,
18+
`TRYAGAIN`) will be retried.
19+
- If `retry_connection_error` is `True`, batch requests will be retried on
20+
connection failures.
21+
22+
Cautions:
23+
- **Server Errors:** Retrying may cause commands targeting the same slot to be executed
24+
out of order.
25+
- **Connection Errors:** Retrying may lead to duplicate executions, since the server might
26+
have already received and processed the request before the error occurred.
27+
28+
Example Scenario:
29+
```
30+
MGET key {key}:1
31+
SET key "value"
32+
```
33+
34+
Expected response when keys are empty:
35+
```
36+
[None, None]
37+
"OK"
38+
```
39+
40+
However, if the slot is migrating, both commands may return an `ASK` error and be
41+
redirected. Upon `ASK` redirection, a multi-key command may return a `TRYAGAIN`
42+
error (triggering a retry), while the `SET` command succeeds immediately. This
43+
can result in an unintended reordering of commands if the first command is retried
44+
after the slot stabilizes:
45+
```
46+
["value", None]
47+
"OK"
48+
```
49+
50+
Note:
51+
Currently, retry strategies are supported only for non-atomic batches.
52+
53+
Default:
54+
Both `retry_server_error` and `retry_connection_error` are set to `False`.
55+
56+
Args:
57+
retry_server_error (bool): If `True`, failed commands with a retriable error (e.g., `TRYAGAIN`)
58+
will be automatically retried.
59+
60+
⚠️ **Warning:** Enabling this flag may cause commands targeting the same slot to execute
61+
out of order.
62+
63+
By default, this is set to `False`.
64+
65+
retry_connection_error (bool): If `True`, batch requests will be retried in case of connection errors.
66+
67+
⚠️ **Warning:** Retrying after a connection error may lead to duplicate executions, since
68+
the server might have already received and processed the request before the error occurred.
69+
70+
By default, this is set to `False`.
71+
72+
"""
73+
74+
def __init__(
75+
self,
76+
retry_server_error: bool = False,
77+
retry_connection_error: bool = False,
78+
):
79+
"""
80+
Initialize a BatchRetryStrategy.
81+
82+
Args:
83+
retry_server_error (bool): If `True`, failed commands with a retriable error (e.g., `TRYAGAIN`)
84+
will be automatically retried.
85+
86+
⚠️ **Warning:** Enabling this flag may cause commands targeting the same slot to execute
87+
out of order.
88+
89+
By default, this is set to `False`.
90+
91+
retry_connection_error (bool): If `True`, batch requests will be retried in case of connection errors.
92+
93+
⚠️ **Warning:** Retrying after a connection error may lead to duplicate executions, since
94+
the server might have already received and processed the request before the error occurred.
95+
96+
By default, this is set to `False`.
97+
98+
"""
99+
self.retry_server_error = retry_server_error
100+
self.retry_connection_error = retry_connection_error
101+
102+
103+
class BaseBatchOptions:
104+
"""
105+
Base options settings class for sending a batch request. Shared settings for standalone and
106+
cluster batch requests.
107+
108+
Args:
109+
timeout (Optional[int]): The duration in milliseconds that the client should wait for the batch request
110+
to complete. This duration encompasses sending the request, awaiting a response from the server,
111+
and any required reconnections or retries. If the specified timeout is exceeded for a pending request,
112+
it will result in a timeout error. If not explicitly set, the client's default request timeout will be used.
113+
"""
114+
115+
def __init__(
116+
self,
117+
timeout: Optional[int] = None,
118+
):
119+
"""
120+
Initialize BaseBatchOptions.
121+
122+
Args:
123+
timeout (Optional[int]): The duration in milliseconds that the client should wait for the batch request
124+
to complete. This duration encompasses sending the request, awaiting a response from the server,
125+
and any required reconnections or retries. If the specified timeout is exceeded for a pending request,
126+
it will result in a timeout error. If not explicitly set, the client's default request timeout will be used.
127+
"""
128+
self.timeout = timeout
129+
130+
131+
class BatchOptions(BaseBatchOptions):
132+
"""
133+
Options for a batch request for a standalone client.
134+
135+
Args:
136+
timeout (Optional[int]): The duration in milliseconds that the client should wait for the batch request
137+
to complete. This duration encompasses sending the request, awaiting a response from the server,
138+
and any required reconnections or retries. If the specified timeout is exceeded for a pending request,
139+
it will result in a timeout error. If not explicitly set, the client's default request timeout will be used.
140+
"""
141+
142+
def __init__(
143+
self,
144+
timeout: Optional[int] = None,
145+
):
146+
"""
147+
Options for a batch request for a standalone client
148+
149+
Args:
150+
timeout (Optional[int]): The duration in milliseconds that the client should wait for the batch request
151+
to complete. This duration encompasses sending the request, awaiting a response from the server,
152+
and any required reconnections or retries. If the specified timeout is exceeded for a pending request,
153+
it will result in a timeout error. If not explicitly set, the client's default request timeout will be used.
154+
"""
155+
super().__init__(timeout)
156+
157+
158+
class ClusterBatchOptions(BaseBatchOptions):
159+
"""
160+
Options for cluster batch operations.
161+
162+
Args:
163+
timeout (Optional[int]): The duration in milliseconds that the client should wait for the batch request
164+
to complete. This duration encompasses sending the request, awaiting a response from the server,
165+
and any required reconnections or retries. If the specified timeout is exceeded for a pending request,
166+
it will result in a timeout error. If not explicitly set, the client's default request timeout will be used.
167+
168+
route (Optional[TSingleNodeRoute]): Configures single-node routing for the batch request. The client
169+
will send the batch to the specified node defined by `route`.
170+
171+
If a redirection error occurs:
172+
173+
- For Atomic Batches (Transactions), the entire transaction will be redirected.
174+
- For Non-Atomic Batches (Pipelines), only the commands that encountered redirection errors
175+
will be redirected.
176+
177+
retry_strategy (Optional[BatchRetryStrategy]): ⚠️ **Please see `BatchRetryStrategy` and read carefully before enabling these
178+
options.**
179+
180+
Defines the retry strategy for handling cluster batch request failures.
181+
182+
This strategy determines whether failed commands should be retried, potentially impacting
183+
execution order.
184+
185+
- If `retry_server_error` is `True`, retriable errors (e.g., TRYAGAIN) will
186+
trigger a retry.
187+
- If `retry_connection_error` is `True`, connection failures will trigger a
188+
retry.
189+
190+
**Warnings:**
191+
192+
- Retrying server errors may cause commands targeting the same slot to execute out of
193+
order.
194+
- Retrying connection errors may lead to duplicate executions, as it is unclear which
195+
commands have already been processed.
196+
197+
**Note:** Currently, retry strategies are supported only for non-atomic batches.
198+
199+
**Recommendation:** It is recommended to increase the timeout in `timeout`
200+
when enabling these strategies.
201+
202+
**Default:** Both `retry_server_error` and `retry_connection_error` are set to
203+
`False`.
204+
205+
"""
206+
207+
def __init__(
208+
self,
209+
timeout: Optional[int] = None,
210+
route: Optional[TSingleNodeRoute] = None,
211+
retry_strategy: Optional[BatchRetryStrategy] = None,
212+
):
213+
"""
214+
Initialize ClusterBatchOptions.
215+
216+
Args:
217+
timeout (Optional[int]): The duration in milliseconds that the client should wait for the batch request
218+
to complete. This duration encompasses sending the request, awaiting a response from the server,
219+
and any required reconnections or retries. If the specified timeout is exceeded for a pending request,
220+
it will result in a timeout error. If not explicitly set, the client's default request timeout will be used.
221+
222+
route (Optional[TSingleNodeRoute]): Configures single-node routing for the batch request. The client
223+
will send the batch to the specified node defined by `route`.
224+
225+
If a redirection error occurs:
226+
227+
- For Atomic Batches (Transactions), the entire transaction will be redirected.
228+
- For Non-Atomic Batches (Pipelines), only the commands that encountered redirection errors
229+
will be redirected.
230+
231+
retry_strategy (Optional[BatchRetryStrategy]): ⚠️ **Please see `BatchRetryStrategy` and read carefully before enabling these
232+
options.**
233+
234+
Defines the retry strategy for handling cluster batch request failures.
235+
236+
This strategy determines whether failed commands should be retried, potentially impacting
237+
execution order.
238+
239+
- If `retry_server_error` is `True`, retriable errors (e.g., TRYAGAIN) will
240+
trigger a retry.
241+
- If `retry_connection_error` is `True`, connection failures will trigger a
242+
retry.
243+
244+
**Warnings:**
245+
246+
- Retrying server errors may cause commands targeting the same slot to execute out of
247+
order.
248+
- Retrying connection errors may lead to duplicate executions, as it is unclear which
249+
commands have already been processed.
250+
251+
**Note:** Currently, retry strategies are supported only for non-atomic batches.
252+
253+
**Recommendation:** It is recommended to increase the timeout in `timeout`
254+
when enabling these strategies.
255+
256+
**Default:** Both `retry_server_error` and `retry_connection_error` are set to
257+
`False`.
258+
"""
259+
super().__init__(timeout)
260+
self.retry_strategy = retry_strategy
261+
self.route = route

0 commit comments

Comments
 (0)