Retry code until it succeeds
npx @tessl/cli install tessl/pypi-tenacity@9.1.00
# Tenacity - Comprehensive Python Retry Library
1
2
Tenacity is a robust Python library that provides decorators and utilities for adding sophisticated retry behavior to functions and code blocks. It offers flexible retry strategies, exponential backoff, customizable stop conditions, and extensive callback mechanisms for both synchronous and asynchronous code.
3
4
## Package Information
5
6
```bash
7
pip install tenacity
8
```
9
10
```python { .api }
11
import tenacity
12
from tenacity import retry, stop_after_attempt, wait_exponential
13
```
14
15
## Basic Usage
16
17
The simplest way to add retry behavior is with the `@retry` decorator:
18
19
```python { .api }
20
from tenacity import retry, stop_after_attempt, wait_fixed
21
22
@retry(stop=stop_after_attempt(3), wait=wait_fixed(1))
23
def unreliable_function():
24
"""Function that might fail but will be retried up to 3 times with 1 second between attempts."""
25
# Your code here
26
pass
27
```
28
29
## Architecture
30
31
Tenacity is built around a modular architecture with four core components:
32
33
### 1. Retry Controllers
34
- **`BaseRetrying`** - Abstract base class for all retry controllers
35
- **`Retrying`** - Standard synchronous retry controller
36
- **`AsyncRetrying`** - Asynchronous retry controller for coroutines
37
- **`TornadoRetrying`** - Tornado web framework integration
38
39
### 2. Retry Strategies
40
Determine when to retry based on exceptions or return values:
41
- Exception-based conditions (`retry_if_exception_type`, `retry_if_exception_message`)
42
- Result-based conditions (`retry_if_result`, `retry_if_not_result`)
43
- Logical combinations (`retry_any`, `retry_all`)
44
- Chain-of-causation support (`retry_if_exception_cause_type`)
45
46
### 3. Stop Conditions
47
Control when to stop retrying:
48
- Attempt-based (`stop_after_attempt`)
49
- Time-based (`stop_after_delay`, `stop_before_delay`)
50
- Event-based (`stop_when_event_set`)
51
- Logical combinations (`stop_any`, `stop_all`)
52
53
### 4. Wait Strategies
54
Define delays between retry attempts:
55
- Fixed delays (`wait_fixed`)
56
- Exponential backoff (`wait_exponential`, `wait_random_exponential`)
57
- Random delays (`wait_random`)
58
- Incremental delays (`wait_incrementing`)
59
- Strategy combinations (`wait_combine`, `wait_chain`)
60
61
## Core Type Definitions
62
63
```python { .api }
64
from typing import Any, Callable, Union, TypeVar, Optional
65
from datetime import timedelta
66
import threading
67
68
# Type aliases for time units
69
time_unit_type = Union[int, float, timedelta]
70
71
# Type variables for wrapped functions
72
WrappedFn = TypeVar('WrappedFn', bound=Callable[..., Any])
73
WrappedFnReturnT = TypeVar('WrappedFnReturnT')
74
75
# Base type aliases for strategy composition
76
RetryBaseT = Union['retry_base', Callable[['RetryCallState'], bool]]
77
StopBaseT = Union['stop_base', Callable[['RetryCallState'], bool]]
78
WaitBaseT = Union['wait_base', Callable[['RetryCallState'], Union[float, int]]]
79
80
# Core state management
81
class RetryCallState:
82
"""Tracks state of a retry session."""
83
start_time: float
84
retry_object: 'BaseRetrying'
85
fn: Callable[..., Any]
86
args: tuple
87
kwargs: dict
88
attempt_number: int
89
outcome: 'Future'
90
outcome_timestamp: Optional[float]
91
idle_for: float
92
next_action: Optional['BaseAction']
93
upcoming_sleep: float
94
seconds_since_start: float
95
96
class Future:
97
"""Container for attempt results."""
98
attempt_number: int
99
failed: bool
100
101
@classmethod
102
def construct(cls, attempt_number: int, value: Any, has_exception: bool) -> 'Future'
103
104
# Exception classes
105
class TryAgain(Exception):
106
"""Raise to force immediate retry regardless of retry condition."""
107
pass
108
109
class RetryError(Exception):
110
"""Raised when all retry attempts are exhausted."""
111
last_attempt: Future
112
113
def reraise(self) -> None:
114
"""Reraise the original exception from the last attempt."""
115
```
116
117
## Main Decorator
118
119
```python { .api }
120
def retry(
121
sleep: Callable[[float], None] = sleep,
122
stop: StopBaseT = stop_never,
123
wait: WaitBaseT = wait_none(),
124
retry: RetryBaseT = retry_if_exception_type(),
125
before: Callable[[RetryCallState], None] = before_nothing,
126
after: Callable[[RetryCallState], None] = after_nothing,
127
before_sleep: Optional[Callable[[RetryCallState], None]] = None,
128
reraise: bool = False,
129
retry_error_cls: type = RetryError,
130
retry_error_callback: Optional[Callable[[RetryCallState], Any]] = None
131
) -> Callable[[WrappedFn], WrappedFn]:
132
"""
133
Main decorator to add retry behavior to functions.
134
135
Auto-detects async/tornado functions and applies appropriate retry controller.
136
137
Parameters:
138
- sleep: Function to use for sleeping between retries
139
- stop: Strategy determining when to stop retrying
140
- wait: Strategy determining how long to wait between retries
141
- retry: Strategy determining whether to retry after a failure
142
- before: Callback executed before each attempt
143
- after: Callback executed after each attempt
144
- before_sleep: Callback executed before sleeping between retries
145
- reraise: If True, reraise original exception instead of RetryError
146
- retry_error_cls: Exception class to raise when retries are exhausted
147
- retry_error_callback: Callback executed when retries are exhausted
148
"""
149
```
150
151
## Core Capability Areas
152
153
### [Core Decorator & Classes](./core-decorator.md)
154
Complete coverage of the `@retry` decorator, `Retrying`, `AsyncRetrying`, `TornadoRetrying` classes, and state management components like `RetryCallState` and `Future`.
155
156
### [Retry Strategies](./retry-strategies.md)
157
All 14+ retry conditions including exception-based (`retry_if_exception_type`), result-based (`retry_if_result`), message-based (`retry_if_exception_message`), and logical combinations (`retry_any`, `retry_all`).
158
159
### [Stop Conditions](./stop-conditions.md)
160
Complete coverage of 7+ stop strategies including attempt limits (`stop_after_attempt`), time limits (`stop_after_delay`, `stop_before_delay`), event-based stopping, and logical combinations.
161
162
### [Wait Strategies](./wait-strategies.md)
163
All 9+ wait/backoff strategies including fixed delays, exponential backoff with jitter, random delays, incremental delays, and strategy composition methods.
164
165
### [Async Support](./async-support.md)
166
Comprehensive async/await support with `AsyncRetrying`, async retry strategies, and integration with asyncio, trio, and other async frameworks.
167
168
### [Callbacks & Hooks](./callbacks-hooks.md)
169
Complete callback system including before/after attempt hooks, before sleep callbacks, logging utilities, and custom callback creation.
170
171
### [Utilities & Helpers](./utilities.md)
172
Utility functions, sleep strategies, time conversion helpers, and other supporting functionality for advanced retry scenarios.
173
174
## Key Features
175
176
- **Flexible Retry Logic**: 14+ retry strategies based on exceptions, return values, or custom conditions
177
- **Sophisticated Timing**: 9+ wait strategies with exponential backoff, jitter, and custom timing
178
- **Async/Await Support**: Native support for coroutines with `AsyncRetrying`
179
- **Framework Integration**: Tornado web framework support via `TornadoRetrying`
180
- **Comprehensive Callbacks**: Before/after/sleep hooks for logging and custom actions
181
- **Logical Composition**: Combine strategies with AND/OR logic
182
- **Type Safety**: Full type annotations and generic support
183
- **Thread Safety**: Built-in threading support with event-based coordination
184
- **Extensive Configuration**: 20+ parameters for fine-tuned retry behavior
185
186
## Common Patterns
187
188
```python { .api }
189
# Exponential backoff with jitter for API calls
190
@retry(
191
stop=stop_after_attempt(5),
192
wait=wait_random_exponential(min=1, max=60),
193
retry=retry_if_exception_type((ConnectionError, TimeoutError))
194
)
195
def call_external_api():
196
pass
197
198
# Database connection with custom retry logic
199
@retry(
200
stop=stop_after_delay(30),
201
wait=wait_exponential(multiplier=1, min=4, max=10),
202
retry=retry_if_exception_type(ConnectionError),
203
before_sleep=before_sleep_log(logger, logging.WARNING)
204
)
205
def connect_to_database():
206
pass
207
208
# Async function with comprehensive retry
209
@retry(
210
stop=stop_any(stop_after_attempt(5), stop_after_delay(60)),
211
wait=wait_combine(wait_fixed(3), wait_random(0, 2)),
212
retry=retry_if_not_result(lambda x: x is not None)
213
)
214
async def fetch_data():
215
pass
216
```
217
218
This documentation provides complete coverage of tenacity's 95+ public API elements, enabling robust retry behavior for any Python application.