0
# Retry Strategies
1
2
Retry strategies determine *when* to retry based on the outcome of function attempts. Tenacity provides 14+ retry conditions that can evaluate exceptions, return values, or custom predicates to decide whether another attempt should be made.
3
4
## Base Classes
5
6
### retry_base
7
8
```python { .api }
9
from tenacity.retry import retry_base
10
11
class retry_base(ABC):
12
"""
13
Abstract base class for all retry strategies.
14
15
Provides logical operators for combining retry conditions
16
and defines the interface all retry strategies must implement.
17
"""
18
19
@abstractmethod
20
def __call__(self, retry_state: RetryCallState) -> bool:
21
"""
22
Determine whether to retry based on current state.
23
24
Parameters:
25
- retry_state: Complete state of current retry session
26
27
Returns:
28
True if another attempt should be made, False to stop retrying
29
"""
30
31
def __and__(self, other: 'retry_base') -> 'retry_all':
32
"""Combine with another condition using AND logic."""
33
34
def __or__(self, other: 'retry_base') -> 'retry_any':
35
"""Combine with another condition using OR logic."""
36
```
37
38
### RetryBaseT Type
39
40
```python { .api }
41
from tenacity.retry import RetryBaseT
42
43
RetryBaseT = Union[retry_base, Callable[[RetryCallState], bool]]
44
```
45
46
## Basic Retry Strategies
47
48
### Always/Never Retry
49
50
```python { .api }
51
from tenacity import retry_always, retry_never
52
53
# Singleton instances - always retry or never retry
54
retry_always: retry_base # Always returns True
55
retry_never: retry_base # Always returns False
56
```
57
58
### Usage Examples
59
60
```python { .api }
61
# Never retry (useful for testing)
62
@retry(retry=retry_never)
63
def no_retries():
64
pass
65
66
# Always retry (combine with stop condition to avoid infinite loops)
67
@retry(retry=retry_always, stop=stop_after_attempt(3))
68
def always_retry_but_limited():
69
pass
70
```
71
72
## Exception-Based Strategies
73
74
### retry_if_exception
75
76
```python { .api }
77
from tenacity import retry_if_exception
78
79
class retry_if_exception(retry_base):
80
"""
81
Retry if exception matches a custom predicate function.
82
83
Most flexible exception-based retry strategy - allows complex
84
exception analysis beyond just type checking.
85
"""
86
87
def __init__(self, predicate: Callable[[BaseException], bool]):
88
"""
89
Initialize with exception predicate.
90
91
Parameters:
92
- predicate: Function that takes an exception and returns bool
93
"""
94
```
95
96
### retry_if_exception_type
97
98
```python { .api }
99
from tenacity import retry_if_exception_type
100
101
class retry_if_exception_type(retry_if_exception):
102
"""
103
Retry if exception is an instance of specified types.
104
105
Most commonly used retry strategy - retries on specific exception types.
106
"""
107
108
def __init__(
109
self,
110
exception_types: Union[type, tuple[type, ...]] = Exception
111
):
112
"""
113
Initialize with exception types to retry on.
114
115
Parameters:
116
- exception_types: Single exception type or tuple of types to retry on
117
Defaults to Exception (retry on any exception)
118
"""
119
```
120
121
### retry_if_not_exception_type
122
123
```python { .api }
124
from tenacity import retry_if_not_exception_type
125
126
class retry_if_not_exception_type(retry_if_exception):
127
"""
128
Retry unless exception is an instance of specified types.
129
130
Inverse of retry_if_exception_type - retries on all exceptions
131
except the specified types.
132
"""
133
134
def __init__(
135
self,
136
exception_types: Union[type, tuple[type, ...]] = Exception
137
):
138
"""
139
Initialize with exception types to NOT retry on.
140
141
Parameters:
142
- exception_types: Exception types that should stop retrying
143
"""
144
```
145
146
### retry_unless_exception_type
147
148
```python { .api }
149
from tenacity import retry_unless_exception_type
150
151
class retry_unless_exception_type(retry_if_exception):
152
"""
153
Retry until exception of specified type is raised.
154
155
Always retries on success, only stops when the specified
156
exception type is encountered. Useful for "retry until error" patterns.
157
"""
158
159
def __init__(
160
self,
161
exception_types: Union[type, tuple[type, ...]] = Exception
162
):
163
"""
164
Initialize with exception types that should stop retrying.
165
166
Parameters:
167
- exception_types: Exception types that indicate completion
168
"""
169
```
170
171
### retry_if_exception_cause_type
172
173
```python { .api }
174
from tenacity import retry_if_exception_cause_type
175
176
class retry_if_exception_cause_type(retry_base):
177
"""
178
Retry if any exception in the cause chain matches specified types.
179
180
Examines the entire exception cause chain (exception.__cause__ and
181
exception.__context__) to find matching exception types.
182
"""
183
184
def __init__(
185
self,
186
exception_types: Union[type, tuple[type, ...]] = Exception
187
):
188
"""
189
Initialize with exception types to search for in cause chain.
190
191
Parameters:
192
- exception_types: Types to look for in exception cause chain
193
"""
194
```
195
196
### Exception Message Matching
197
198
```python { .api }
199
from tenacity import retry_if_exception_message, retry_if_not_exception_message
200
import re
201
from typing import Pattern
202
203
class retry_if_exception_message(retry_if_exception):
204
"""
205
Retry if exception message equals string or matches regex pattern.
206
207
Provides fine-grained control based on exception message content.
208
"""
209
210
def __init__(
211
self,
212
message: Optional[str] = None,
213
match: Optional[Union[str, Pattern[str]]] = None
214
):
215
"""
216
Initialize with message matching criteria.
217
218
Parameters:
219
- message: Exact message string to match (mutually exclusive with match)
220
- match: Regex pattern to match against message (mutually exclusive with message)
221
222
Note: Exactly one of message or match must be provided.
223
"""
224
225
class retry_if_not_exception_message(retry_if_exception_message):
226
"""
227
Retry until exception message equals string or matches regex pattern.
228
229
Always retries on success, only stops when exception message matches.
230
"""
231
```
232
233
## Result-Based Strategies
234
235
### retry_if_result
236
237
```python { .api }
238
from tenacity import retry_if_result
239
240
class retry_if_result(retry_base):
241
"""
242
Retry if successful result matches a predicate function.
243
244
Allows retrying based on return values rather than exceptions.
245
Useful for APIs that return error codes or sentinel values.
246
"""
247
248
def __init__(self, predicate: Callable[[Any], bool]):
249
"""
250
Initialize with result predicate.
251
252
Parameters:
253
- predicate: Function that takes return value and returns bool
254
True means retry, False means accept result
255
"""
256
```
257
258
### retry_if_not_result
259
260
```python { .api }
261
from tenacity import retry_if_not_result
262
263
class retry_if_not_result(retry_base):
264
"""
265
Retry if successful result does NOT match a predicate function.
266
267
Inverse of retry_if_result - retries until the predicate returns True.
268
"""
269
270
def __init__(self, predicate: Callable[[Any], bool]):
271
"""
272
Initialize with result predicate.
273
274
Parameters:
275
- predicate: Function that takes return value and returns bool
276
False means retry, True means accept result
277
"""
278
```
279
280
## Logical Combinations
281
282
### retry_any
283
284
```python { .api }
285
from tenacity import retry_any
286
287
class retry_any(retry_base):
288
"""
289
Retry if ANY of the provided conditions are true (OR logic).
290
291
Combines multiple retry strategies with logical OR.
292
"""
293
294
def __init__(self, *retries: retry_base):
295
"""
296
Initialize with retry strategies to combine.
297
298
Parameters:
299
- *retries: Variable number of retry strategies
300
301
Returns True if any strategy returns True.
302
"""
303
```
304
305
### retry_all
306
307
```python { .api }
308
from tenacity import retry_all
309
310
class retry_all(retry_base):
311
"""
312
Retry if ALL of the provided conditions are true (AND logic).
313
314
Combines multiple retry strategies with logical AND.
315
"""
316
317
def __init__(self, *retries: retry_base):
318
"""
319
Initialize with retry strategies to combine.
320
321
Parameters:
322
- *retries: Variable number of retry strategies
323
324
Returns True only if all strategies return True.
325
"""
326
```
327
328
## Usage Examples
329
330
### Exception Type Strategies
331
332
```python { .api }
333
# Retry on specific exception types
334
@retry(retry=retry_if_exception_type((ConnectionError, TimeoutError)))
335
def network_call():
336
pass
337
338
# Retry on any exception except KeyboardInterrupt
339
@retry(retry=retry_if_not_exception_type(KeyboardInterrupt))
340
def interruptible_operation():
341
pass
342
343
# Retry until ValueError is raised (success or other exceptions continue)
344
@retry(retry=retry_unless_exception_type(ValueError))
345
def retry_until_validation_error():
346
pass
347
```
348
349
### Exception Message Strategies
350
351
```python { .api }
352
# Retry on specific error message
353
@retry(retry=retry_if_exception_message(message="Connection timeout"))
354
def api_with_timeout():
355
pass
356
357
# Retry on messages matching regex pattern
358
@retry(retry=retry_if_exception_message(match=r"rate limit.*exceeded"))
359
def rate_limited_api():
360
pass
361
362
# Retry until specific error message appears
363
@retry(retry=retry_if_not_exception_message(match=r"authentication.*failed"))
364
def retry_until_auth_fails():
365
pass
366
```
367
368
### Result-Based Strategies
369
370
```python { .api }
371
# Retry if result is None
372
@retry(retry=retry_if_result(lambda x: x is None))
373
def get_data():
374
pass
375
376
# Retry until result meets criteria
377
@retry(retry=retry_if_not_result(lambda x: x > 0))
378
def get_positive_number():
379
pass
380
381
# Retry on specific return values
382
@retry(retry=retry_if_result(lambda x: x in ['PENDING', 'PROCESSING']))
383
def check_job_status():
384
pass
385
```
386
387
### Custom Predicate Strategies
388
389
```python { .api }
390
# Custom exception analysis
391
def is_retryable_error(exc):
392
return (
393
isinstance(exc, ConnectionError) or
394
(isinstance(exc, ValueError) and "temporary" in str(exc))
395
)
396
397
@retry(retry=retry_if_exception(is_retryable_error))
398
def complex_operation():
399
pass
400
401
# Custom result analysis
402
def is_incomplete_result(result):
403
return isinstance(result, dict) and result.get('status') == 'incomplete'
404
405
@retry(retry=retry_if_result(is_incomplete_result))
406
def fetch_complete_data():
407
pass
408
```
409
410
### Logical Combinations
411
412
```python { .api }
413
# Retry on connection errors OR timeout errors
414
@retry(retry=retry_any(
415
retry_if_exception_type(ConnectionError),
416
retry_if_exception_type(TimeoutError)
417
))
418
def network_operation():
419
pass
420
421
# Retry if BOTH conditions are met
422
@retry(retry=retry_all(
423
retry_if_exception_type(ValueError),
424
retry_if_exception_message(match=r"retry.*possible")
425
))
426
def strict_retry_conditions():
427
pass
428
429
# Complex nested logic
430
@retry(retry=retry_any(
431
retry_if_exception_type(ConnectionError),
432
retry_all(
433
retry_if_exception_type(ValueError),
434
retry_if_exception_message(message="Temporary failure")
435
),
436
retry_if_result(lambda x: x is None)
437
))
438
def complex_retry_logic():
439
pass
440
```
441
442
### Operator Overloading
443
444
```python { .api }
445
# Use & and | operators for logical combinations
446
connection_errors = retry_if_exception_type((ConnectionError, TimeoutError))
447
temp_failures = retry_if_exception_message(match=r"temp.*fail")
448
449
# AND logic using & operator
450
strict_retry = connection_errors & temp_failures
451
452
# OR logic using | operator
453
lenient_retry = connection_errors | temp_failures
454
455
@retry(retry=lenient_retry)
456
def flexible_operation():
457
pass
458
```
459
460
### Exception Cause Chain Analysis
461
462
```python { .api }
463
# Retry if any exception in cause chain is a ConnectionError
464
@retry(retry=retry_if_exception_cause_type(ConnectionError))
465
def wrapped_network_call():
466
try:
467
network_operation()
468
except ConnectionError as e:
469
raise ValueError("Network failed") from e
470
```
471
472
### Advanced Patterns
473
474
```python { .api }
475
# Retry different exceptions with different conditions
476
http_errors = retry_if_exception_type((requests.ConnectionError, requests.Timeout))
477
server_errors = retry_if_exception_message(match=r"5\d\d.*error")
478
temp_results = retry_if_result(lambda x: x.get('status') == 'temporary')
479
480
comprehensive_retry = http_errors | server_errors | temp_results
481
482
@retry(
483
retry=comprehensive_retry,
484
stop=stop_after_attempt(5),
485
wait=wait_exponential(multiplier=1, min=4, max=10)
486
)
487
def robust_api_call():
488
pass
489
```
490
491
## Force Retry with TryAgain
492
493
```python { .api }
494
from tenacity import TryAgain
495
496
class TryAgain(Exception):
497
"""
498
Exception to force immediate retry regardless of retry condition.
499
500
Raise this exception to bypass all retry strategy evaluation
501
and force another attempt (subject to stop conditions).
502
"""
503
pass
504
505
# Usage example
506
@retry(stop=stop_after_attempt(3))
507
def conditional_retry():
508
if some_condition():
509
raise TryAgain # Forces retry even if retry strategy would say no
510
# Normal logic here
511
```
512
513
This comprehensive coverage of retry strategies provides complete control over when retry attempts should be made, enabling sophisticated retry logic based on exceptions, return values, and custom business logic.