python-backoff 2.3.0__tar.gz → 2.3.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python_backoff-2.3.0 → python_backoff-2.3.1}/.gitignore +0 -2
- {python_backoff-2.3.0 → python_backoff-2.3.1}/PKG-INFO +107 -56
- {python_backoff-2.3.0 → python_backoff-2.3.1}/README.rst +106 -55
- {python_backoff-2.3.0 → python_backoff-2.3.1}/backoff/__init__.py +11 -11
- {python_backoff-2.3.0 → python_backoff-2.3.1}/backoff/_async.py +49 -36
- {python_backoff-2.3.0 → python_backoff-2.3.1}/backoff/_common.py +15 -14
- {python_backoff-2.3.0 → python_backoff-2.3.1}/backoff/_decorator.py +34 -29
- {python_backoff-2.3.0 → python_backoff-2.3.1}/backoff/_jitter.py +0 -2
- {python_backoff-2.3.0 → python_backoff-2.3.1}/backoff/_sync.py +47 -33
- {python_backoff-2.3.0 → python_backoff-2.3.1}/backoff/_typing.py +15 -17
- {python_backoff-2.3.0 → python_backoff-2.3.1}/backoff/_wait_gen.py +0 -4
- {python_backoff-2.3.0 → python_backoff-2.3.1}/backoff/types.py +1 -2
- {python_backoff-2.3.0 → python_backoff-2.3.1}/pyproject.toml +26 -8
- {python_backoff-2.3.0 → python_backoff-2.3.1}/tests/common.py +3 -4
- {python_backoff-2.3.0 → python_backoff-2.3.1}/tests/test_backoff.py +265 -234
- {python_backoff-2.3.0 → python_backoff-2.3.1}/tests/test_backoff_async.py +262 -238
- {python_backoff-2.3.0 → python_backoff-2.3.1}/tests/test_integration.py +0 -2
- {python_backoff-2.3.0 → python_backoff-2.3.1}/tests/test_jitter.py +0 -1
- python_backoff-2.3.1/tests/test_package.py +32 -0
- {python_backoff-2.3.0 → python_backoff-2.3.1}/tests/test_types.py +0 -2
- {python_backoff-2.3.0 → python_backoff-2.3.1}/tests/test_typing.py +1 -0
- {python_backoff-2.3.0 → python_backoff-2.3.1}/tests/test_wait_gen.py +9 -10
- {python_backoff-2.3.0 → python_backoff-2.3.1}/LICENSE +0 -0
- {python_backoff-2.3.0 → python_backoff-2.3.1}/backoff/py.typed +0 -0
- {python_backoff-2.3.0 → python_backoff-2.3.1}/tests/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-backoff
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.1
|
|
4
4
|
Summary: Function decoration for backoff and retry
|
|
5
5
|
Project-URL: Documentation, https://python-backoff.github.io/backoff
|
|
6
6
|
Project-URL: Repository, https://github.com/python-backoff/backoff
|
|
@@ -58,7 +58,7 @@ for asynchronous code.
|
|
|
58
58
|
Examples
|
|
59
59
|
========
|
|
60
60
|
|
|
61
|
-
Since Kenneth Reitz's `requests <
|
|
61
|
+
Since Kenneth Reitz's `requests <https://requests.readthedocs.io>`_ module
|
|
62
62
|
has become a defacto standard for synchronous HTTP clients in Python,
|
|
63
63
|
networking examples below are written using it, but it is in no way required
|
|
64
64
|
by the backoff module.
|
|
@@ -72,8 +72,10 @@ is raised. Here's an example using exponential backoff when any
|
|
|
72
72
|
|
|
73
73
|
.. code-block:: python
|
|
74
74
|
|
|
75
|
-
@backoff.on_exception(
|
|
76
|
-
|
|
75
|
+
@backoff.on_exception(
|
|
76
|
+
backoff.expo,
|
|
77
|
+
requests.exceptions.RequestException,
|
|
78
|
+
)
|
|
77
79
|
def get_url(url):
|
|
78
80
|
return requests.get(url)
|
|
79
81
|
|
|
@@ -82,9 +84,13 @@ the same backoff behavior is desired for more than one exception type:
|
|
|
82
84
|
|
|
83
85
|
.. code-block:: python
|
|
84
86
|
|
|
85
|
-
@backoff.on_exception(
|
|
86
|
-
|
|
87
|
-
|
|
87
|
+
@backoff.on_exception(
|
|
88
|
+
backoff.expo,
|
|
89
|
+
(
|
|
90
|
+
requests.exceptions.Timeout,
|
|
91
|
+
requests.exceptions.ConnectionError,
|
|
92
|
+
),
|
|
93
|
+
)
|
|
88
94
|
def get_url(url):
|
|
89
95
|
return requests.get(url)
|
|
90
96
|
|
|
@@ -98,9 +104,11 @@ of total time in seconds that can elapse before giving up.
|
|
|
98
104
|
|
|
99
105
|
.. code-block:: python
|
|
100
106
|
|
|
101
|
-
@backoff.on_exception(
|
|
102
|
-
|
|
103
|
-
|
|
107
|
+
@backoff.on_exception(
|
|
108
|
+
backoff.expo,
|
|
109
|
+
requests.exceptions.RequestException,
|
|
110
|
+
max_time=60,
|
|
111
|
+
)
|
|
104
112
|
def get_url(url):
|
|
105
113
|
return requests.get(url)
|
|
106
114
|
|
|
@@ -110,10 +118,12 @@ to make to the target function before giving up.
|
|
|
110
118
|
|
|
111
119
|
.. code-block:: python
|
|
112
120
|
|
|
113
|
-
@backoff.on_exception(
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
121
|
+
@backoff.on_exception(
|
|
122
|
+
backoff.expo,
|
|
123
|
+
requests.exceptions.RequestException,
|
|
124
|
+
max_tries=8,
|
|
125
|
+
jitter=None,
|
|
126
|
+
)
|
|
117
127
|
def get_url(url):
|
|
118
128
|
return requests.get(url)
|
|
119
129
|
|
|
@@ -129,10 +139,13 @@ be retried:
|
|
|
129
139
|
def fatal_code(e):
|
|
130
140
|
return 400 <= e.response.status_code < 500
|
|
131
141
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
142
|
+
|
|
143
|
+
@backoff.on_exception(
|
|
144
|
+
backoff.expo,
|
|
145
|
+
requests.exceptions.RequestException,
|
|
146
|
+
max_time=300,
|
|
147
|
+
giveup=fatal_code,
|
|
148
|
+
)
|
|
136
149
|
def get_url(url):
|
|
137
150
|
return requests.get(url)
|
|
138
151
|
|
|
@@ -150,11 +163,14 @@ case, regardless of the logic in the `on_exception` handler.
|
|
|
150
163
|
def fatal_code(e):
|
|
151
164
|
return 400 <= e.response.status_code < 500
|
|
152
165
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
166
|
+
|
|
167
|
+
@backoff.on_exception(
|
|
168
|
+
backoff.expo,
|
|
169
|
+
requests.exceptions.RequestException,
|
|
170
|
+
max_time=300,
|
|
171
|
+
raise_on_giveup=False,
|
|
172
|
+
giveup=fatal_code,
|
|
173
|
+
)
|
|
158
174
|
def get_url(url):
|
|
159
175
|
return requests.get(url)
|
|
160
176
|
|
|
@@ -174,7 +190,11 @@ return value of the target function is the empty list:
|
|
|
174
190
|
|
|
175
191
|
.. code-block:: python
|
|
176
192
|
|
|
177
|
-
@backoff.on_predicate(
|
|
193
|
+
@backoff.on_predicate(
|
|
194
|
+
backoff.fibo,
|
|
195
|
+
lambda x: x == [],
|
|
196
|
+
max_value=13,
|
|
197
|
+
)
|
|
178
198
|
def poll_for_messages(queue):
|
|
179
199
|
return queue.get()
|
|
180
200
|
|
|
@@ -196,7 +216,11 @@ gets a non-falsey result could be defined like like this:
|
|
|
196
216
|
|
|
197
217
|
.. code-block:: python
|
|
198
218
|
|
|
199
|
-
@backoff.on_predicate(
|
|
219
|
+
@backoff.on_predicate(
|
|
220
|
+
backoff.constant,
|
|
221
|
+
jitter=None,
|
|
222
|
+
interval=1,
|
|
223
|
+
)
|
|
200
224
|
def poll_for_message(queue):
|
|
201
225
|
return queue.get()
|
|
202
226
|
|
|
@@ -249,12 +273,16 @@ backoff behavior for different cases:
|
|
|
249
273
|
.. code-block:: python
|
|
250
274
|
|
|
251
275
|
@backoff.on_predicate(backoff.fibo, max_value=13)
|
|
252
|
-
@backoff.on_exception(
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
276
|
+
@backoff.on_exception(
|
|
277
|
+
backoff.expo,
|
|
278
|
+
requests.exceptions.HTTPError,
|
|
279
|
+
max_time=60,
|
|
280
|
+
)
|
|
281
|
+
@backoff.on_exception(
|
|
282
|
+
backoff.expo,
|
|
283
|
+
requests.exceptions.Timeout,
|
|
284
|
+
max_time=300,
|
|
285
|
+
)
|
|
258
286
|
def poll_for_message(queue):
|
|
259
287
|
return queue.get()
|
|
260
288
|
|
|
@@ -277,9 +305,13 @@ runtime to obtain the value:
|
|
|
277
305
|
# and that it has a dictionary-like 'config' property
|
|
278
306
|
return app.config["BACKOFF_MAX_TIME"]
|
|
279
307
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
308
|
+
|
|
309
|
+
@backoff.on_exception(
|
|
310
|
+
backoff.expo,
|
|
311
|
+
ValueError,
|
|
312
|
+
max_time=lookup_max_time,
|
|
313
|
+
)
|
|
314
|
+
def my_function(): ...
|
|
283
315
|
|
|
284
316
|
Event handlers
|
|
285
317
|
--------------
|
|
@@ -307,13 +339,18 @@ implemented like so:
|
|
|
307
339
|
.. code-block:: python
|
|
308
340
|
|
|
309
341
|
def backoff_hdlr(details):
|
|
310
|
-
print
|
|
311
|
-
|
|
312
|
-
|
|
342
|
+
print(
|
|
343
|
+
"Backing off {wait:0.1f} seconds after {tries} tries "
|
|
344
|
+
"calling function {target} with args {args} and kwargs "
|
|
345
|
+
"{kwargs}".format(**details)
|
|
346
|
+
)
|
|
347
|
+
|
|
313
348
|
|
|
314
|
-
@backoff.on_exception(
|
|
315
|
-
|
|
316
|
-
|
|
349
|
+
@backoff.on_exception(
|
|
350
|
+
backoff.expo,
|
|
351
|
+
requests.exceptions.RequestException,
|
|
352
|
+
on_backoff=backoff_hdlr,
|
|
353
|
+
)
|
|
317
354
|
def get_url(url):
|
|
318
355
|
return requests.get(url)
|
|
319
356
|
|
|
@@ -325,9 +362,14 @@ handler functions as the value of the ``on_backoff`` keyword arg:
|
|
|
325
362
|
|
|
326
363
|
.. code-block:: python
|
|
327
364
|
|
|
328
|
-
@backoff.on_exception(
|
|
329
|
-
|
|
330
|
-
|
|
365
|
+
@backoff.on_exception(
|
|
366
|
+
backoff.expo,
|
|
367
|
+
requests.exceptions.RequestException,
|
|
368
|
+
on_backoff=[
|
|
369
|
+
backoff_hdlr1,
|
|
370
|
+
backoff_hdlr2,
|
|
371
|
+
],
|
|
372
|
+
)
|
|
331
373
|
def get_url(url):
|
|
332
374
|
return requests.get(url)
|
|
333
375
|
|
|
@@ -358,9 +400,13 @@ asynchronous HTTP client/server library.
|
|
|
358
400
|
|
|
359
401
|
.. code-block:: python
|
|
360
402
|
|
|
361
|
-
@backoff.on_exception(
|
|
403
|
+
@backoff.on_exception(
|
|
404
|
+
backoff.expo,
|
|
405
|
+
aiohttp.ClientError,
|
|
406
|
+
max_time=60,
|
|
407
|
+
)
|
|
362
408
|
async def get_url(url):
|
|
363
|
-
async with aiohttp.ClientSession(raise_for_status=True) as session:
|
|
409
|
+
async with aiohttp.ClientSession(raise_for_status=True) as session: # noqa: SIM117
|
|
364
410
|
async with session.get(url) as response:
|
|
365
411
|
return await response.text()
|
|
366
412
|
|
|
@@ -375,7 +421,7 @@ as:
|
|
|
375
421
|
|
|
376
422
|
.. code-block:: python
|
|
377
423
|
|
|
378
|
-
logging.getLogger(
|
|
424
|
+
logging.getLogger("backoff").addHandler(logging.StreamHandler())
|
|
379
425
|
|
|
380
426
|
The default logging level is INFO, which corresponds to logging
|
|
381
427
|
anytime a retry event occurs. If you would instead like to log
|
|
@@ -383,7 +429,7 @@ only when a giveup event occurs, set the logger level to ERROR.
|
|
|
383
429
|
|
|
384
430
|
.. code-block:: python
|
|
385
431
|
|
|
386
|
-
logging.getLogger(
|
|
432
|
+
logging.getLogger("backoff").setLevel(logging.ERROR)
|
|
387
433
|
|
|
388
434
|
It is also possible to specify an alternate logger with the ``logger``
|
|
389
435
|
keyword argument. If a string value is specified the logger will be
|
|
@@ -391,25 +437,30 @@ looked up by name.
|
|
|
391
437
|
|
|
392
438
|
.. code-block:: python
|
|
393
439
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
440
|
+
@backoff.on_exception(
|
|
441
|
+
backoff.expo,
|
|
442
|
+
requests.exceptions.RequestException,
|
|
443
|
+
logger="my_logger",
|
|
444
|
+
)
|
|
445
|
+
def my_function(): ...
|
|
398
446
|
|
|
399
447
|
It is also supported to specify a Logger (or LoggerAdapter) object
|
|
400
448
|
directly.
|
|
401
449
|
|
|
402
450
|
.. code-block:: python
|
|
403
451
|
|
|
404
|
-
my_logger = logging.getLogger(
|
|
452
|
+
my_logger = logging.getLogger("my_logger")
|
|
405
453
|
my_handler = logging.StreamHandler()
|
|
406
454
|
my_logger.addHandler(my_handler)
|
|
407
455
|
my_logger.setLevel(logging.ERROR)
|
|
408
456
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
457
|
+
|
|
458
|
+
@backoff.on_exception(
|
|
459
|
+
backoff.expo,
|
|
460
|
+
requests.exceptions.RequestException,
|
|
461
|
+
logger=my_logger,
|
|
462
|
+
)
|
|
463
|
+
def my_function(): ...
|
|
413
464
|
|
|
414
465
|
Default logging can be disabled all together by specifying
|
|
415
466
|
``logger=None``. In this case, if desired alternative logging behavior
|
|
@@ -26,7 +26,7 @@ for asynchronous code.
|
|
|
26
26
|
Examples
|
|
27
27
|
========
|
|
28
28
|
|
|
29
|
-
Since Kenneth Reitz's `requests <
|
|
29
|
+
Since Kenneth Reitz's `requests <https://requests.readthedocs.io>`_ module
|
|
30
30
|
has become a defacto standard for synchronous HTTP clients in Python,
|
|
31
31
|
networking examples below are written using it, but it is in no way required
|
|
32
32
|
by the backoff module.
|
|
@@ -40,8 +40,10 @@ is raised. Here's an example using exponential backoff when any
|
|
|
40
40
|
|
|
41
41
|
.. code-block:: python
|
|
42
42
|
|
|
43
|
-
@backoff.on_exception(
|
|
44
|
-
|
|
43
|
+
@backoff.on_exception(
|
|
44
|
+
backoff.expo,
|
|
45
|
+
requests.exceptions.RequestException,
|
|
46
|
+
)
|
|
45
47
|
def get_url(url):
|
|
46
48
|
return requests.get(url)
|
|
47
49
|
|
|
@@ -50,9 +52,13 @@ the same backoff behavior is desired for more than one exception type:
|
|
|
50
52
|
|
|
51
53
|
.. code-block:: python
|
|
52
54
|
|
|
53
|
-
@backoff.on_exception(
|
|
54
|
-
|
|
55
|
-
|
|
55
|
+
@backoff.on_exception(
|
|
56
|
+
backoff.expo,
|
|
57
|
+
(
|
|
58
|
+
requests.exceptions.Timeout,
|
|
59
|
+
requests.exceptions.ConnectionError,
|
|
60
|
+
),
|
|
61
|
+
)
|
|
56
62
|
def get_url(url):
|
|
57
63
|
return requests.get(url)
|
|
58
64
|
|
|
@@ -66,9 +72,11 @@ of total time in seconds that can elapse before giving up.
|
|
|
66
72
|
|
|
67
73
|
.. code-block:: python
|
|
68
74
|
|
|
69
|
-
@backoff.on_exception(
|
|
70
|
-
|
|
71
|
-
|
|
75
|
+
@backoff.on_exception(
|
|
76
|
+
backoff.expo,
|
|
77
|
+
requests.exceptions.RequestException,
|
|
78
|
+
max_time=60,
|
|
79
|
+
)
|
|
72
80
|
def get_url(url):
|
|
73
81
|
return requests.get(url)
|
|
74
82
|
|
|
@@ -78,10 +86,12 @@ to make to the target function before giving up.
|
|
|
78
86
|
|
|
79
87
|
.. code-block:: python
|
|
80
88
|
|
|
81
|
-
@backoff.on_exception(
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
89
|
+
@backoff.on_exception(
|
|
90
|
+
backoff.expo,
|
|
91
|
+
requests.exceptions.RequestException,
|
|
92
|
+
max_tries=8,
|
|
93
|
+
jitter=None,
|
|
94
|
+
)
|
|
85
95
|
def get_url(url):
|
|
86
96
|
return requests.get(url)
|
|
87
97
|
|
|
@@ -97,10 +107,13 @@ be retried:
|
|
|
97
107
|
def fatal_code(e):
|
|
98
108
|
return 400 <= e.response.status_code < 500
|
|
99
109
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
110
|
+
|
|
111
|
+
@backoff.on_exception(
|
|
112
|
+
backoff.expo,
|
|
113
|
+
requests.exceptions.RequestException,
|
|
114
|
+
max_time=300,
|
|
115
|
+
giveup=fatal_code,
|
|
116
|
+
)
|
|
104
117
|
def get_url(url):
|
|
105
118
|
return requests.get(url)
|
|
106
119
|
|
|
@@ -118,11 +131,14 @@ case, regardless of the logic in the `on_exception` handler.
|
|
|
118
131
|
def fatal_code(e):
|
|
119
132
|
return 400 <= e.response.status_code < 500
|
|
120
133
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
134
|
+
|
|
135
|
+
@backoff.on_exception(
|
|
136
|
+
backoff.expo,
|
|
137
|
+
requests.exceptions.RequestException,
|
|
138
|
+
max_time=300,
|
|
139
|
+
raise_on_giveup=False,
|
|
140
|
+
giveup=fatal_code,
|
|
141
|
+
)
|
|
126
142
|
def get_url(url):
|
|
127
143
|
return requests.get(url)
|
|
128
144
|
|
|
@@ -142,7 +158,11 @@ return value of the target function is the empty list:
|
|
|
142
158
|
|
|
143
159
|
.. code-block:: python
|
|
144
160
|
|
|
145
|
-
@backoff.on_predicate(
|
|
161
|
+
@backoff.on_predicate(
|
|
162
|
+
backoff.fibo,
|
|
163
|
+
lambda x: x == [],
|
|
164
|
+
max_value=13,
|
|
165
|
+
)
|
|
146
166
|
def poll_for_messages(queue):
|
|
147
167
|
return queue.get()
|
|
148
168
|
|
|
@@ -164,7 +184,11 @@ gets a non-falsey result could be defined like like this:
|
|
|
164
184
|
|
|
165
185
|
.. code-block:: python
|
|
166
186
|
|
|
167
|
-
@backoff.on_predicate(
|
|
187
|
+
@backoff.on_predicate(
|
|
188
|
+
backoff.constant,
|
|
189
|
+
jitter=None,
|
|
190
|
+
interval=1,
|
|
191
|
+
)
|
|
168
192
|
def poll_for_message(queue):
|
|
169
193
|
return queue.get()
|
|
170
194
|
|
|
@@ -217,12 +241,16 @@ backoff behavior for different cases:
|
|
|
217
241
|
.. code-block:: python
|
|
218
242
|
|
|
219
243
|
@backoff.on_predicate(backoff.fibo, max_value=13)
|
|
220
|
-
@backoff.on_exception(
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
244
|
+
@backoff.on_exception(
|
|
245
|
+
backoff.expo,
|
|
246
|
+
requests.exceptions.HTTPError,
|
|
247
|
+
max_time=60,
|
|
248
|
+
)
|
|
249
|
+
@backoff.on_exception(
|
|
250
|
+
backoff.expo,
|
|
251
|
+
requests.exceptions.Timeout,
|
|
252
|
+
max_time=300,
|
|
253
|
+
)
|
|
226
254
|
def poll_for_message(queue):
|
|
227
255
|
return queue.get()
|
|
228
256
|
|
|
@@ -245,9 +273,13 @@ runtime to obtain the value:
|
|
|
245
273
|
# and that it has a dictionary-like 'config' property
|
|
246
274
|
return app.config["BACKOFF_MAX_TIME"]
|
|
247
275
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
276
|
+
|
|
277
|
+
@backoff.on_exception(
|
|
278
|
+
backoff.expo,
|
|
279
|
+
ValueError,
|
|
280
|
+
max_time=lookup_max_time,
|
|
281
|
+
)
|
|
282
|
+
def my_function(): ...
|
|
251
283
|
|
|
252
284
|
Event handlers
|
|
253
285
|
--------------
|
|
@@ -275,13 +307,18 @@ implemented like so:
|
|
|
275
307
|
.. code-block:: python
|
|
276
308
|
|
|
277
309
|
def backoff_hdlr(details):
|
|
278
|
-
print
|
|
279
|
-
|
|
280
|
-
|
|
310
|
+
print(
|
|
311
|
+
"Backing off {wait:0.1f} seconds after {tries} tries "
|
|
312
|
+
"calling function {target} with args {args} and kwargs "
|
|
313
|
+
"{kwargs}".format(**details)
|
|
314
|
+
)
|
|
315
|
+
|
|
281
316
|
|
|
282
|
-
@backoff.on_exception(
|
|
283
|
-
|
|
284
|
-
|
|
317
|
+
@backoff.on_exception(
|
|
318
|
+
backoff.expo,
|
|
319
|
+
requests.exceptions.RequestException,
|
|
320
|
+
on_backoff=backoff_hdlr,
|
|
321
|
+
)
|
|
285
322
|
def get_url(url):
|
|
286
323
|
return requests.get(url)
|
|
287
324
|
|
|
@@ -293,9 +330,14 @@ handler functions as the value of the ``on_backoff`` keyword arg:
|
|
|
293
330
|
|
|
294
331
|
.. code-block:: python
|
|
295
332
|
|
|
296
|
-
@backoff.on_exception(
|
|
297
|
-
|
|
298
|
-
|
|
333
|
+
@backoff.on_exception(
|
|
334
|
+
backoff.expo,
|
|
335
|
+
requests.exceptions.RequestException,
|
|
336
|
+
on_backoff=[
|
|
337
|
+
backoff_hdlr1,
|
|
338
|
+
backoff_hdlr2,
|
|
339
|
+
],
|
|
340
|
+
)
|
|
299
341
|
def get_url(url):
|
|
300
342
|
return requests.get(url)
|
|
301
343
|
|
|
@@ -326,9 +368,13 @@ asynchronous HTTP client/server library.
|
|
|
326
368
|
|
|
327
369
|
.. code-block:: python
|
|
328
370
|
|
|
329
|
-
@backoff.on_exception(
|
|
371
|
+
@backoff.on_exception(
|
|
372
|
+
backoff.expo,
|
|
373
|
+
aiohttp.ClientError,
|
|
374
|
+
max_time=60,
|
|
375
|
+
)
|
|
330
376
|
async def get_url(url):
|
|
331
|
-
async with aiohttp.ClientSession(raise_for_status=True) as session:
|
|
377
|
+
async with aiohttp.ClientSession(raise_for_status=True) as session: # noqa: SIM117
|
|
332
378
|
async with session.get(url) as response:
|
|
333
379
|
return await response.text()
|
|
334
380
|
|
|
@@ -343,7 +389,7 @@ as:
|
|
|
343
389
|
|
|
344
390
|
.. code-block:: python
|
|
345
391
|
|
|
346
|
-
logging.getLogger(
|
|
392
|
+
logging.getLogger("backoff").addHandler(logging.StreamHandler())
|
|
347
393
|
|
|
348
394
|
The default logging level is INFO, which corresponds to logging
|
|
349
395
|
anytime a retry event occurs. If you would instead like to log
|
|
@@ -351,7 +397,7 @@ only when a giveup event occurs, set the logger level to ERROR.
|
|
|
351
397
|
|
|
352
398
|
.. code-block:: python
|
|
353
399
|
|
|
354
|
-
logging.getLogger(
|
|
400
|
+
logging.getLogger("backoff").setLevel(logging.ERROR)
|
|
355
401
|
|
|
356
402
|
It is also possible to specify an alternate logger with the ``logger``
|
|
357
403
|
keyword argument. If a string value is specified the logger will be
|
|
@@ -359,25 +405,30 @@ looked up by name.
|
|
|
359
405
|
|
|
360
406
|
.. code-block:: python
|
|
361
407
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
408
|
+
@backoff.on_exception(
|
|
409
|
+
backoff.expo,
|
|
410
|
+
requests.exceptions.RequestException,
|
|
411
|
+
logger="my_logger",
|
|
412
|
+
)
|
|
413
|
+
def my_function(): ...
|
|
366
414
|
|
|
367
415
|
It is also supported to specify a Logger (or LoggerAdapter) object
|
|
368
416
|
directly.
|
|
369
417
|
|
|
370
418
|
.. code-block:: python
|
|
371
419
|
|
|
372
|
-
my_logger = logging.getLogger(
|
|
420
|
+
my_logger = logging.getLogger("my_logger")
|
|
373
421
|
my_handler = logging.StreamHandler()
|
|
374
422
|
my_logger.addHandler(my_handler)
|
|
375
423
|
my_logger.setLevel(logging.ERROR)
|
|
376
424
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
425
|
+
|
|
426
|
+
@backoff.on_exception(
|
|
427
|
+
backoff.expo,
|
|
428
|
+
requests.exceptions.RequestException,
|
|
429
|
+
logger=my_logger,
|
|
430
|
+
)
|
|
431
|
+
def my_function(): ...
|
|
381
432
|
|
|
382
433
|
Default logging can be disabled all together by specifying
|
|
383
434
|
``logger=None``. In this case, if desired alternative logging behavior
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# coding:utf-8
|
|
2
1
|
"""
|
|
3
2
|
Function decoration for backoff and retry
|
|
4
3
|
|
|
@@ -12,20 +11,21 @@ polling resources for externally generated content.
|
|
|
12
11
|
For examples and full documentation see the README at
|
|
13
12
|
https://github.com/python-backoff/backoff
|
|
14
13
|
"""
|
|
14
|
+
|
|
15
15
|
from backoff._decorator import on_exception, on_predicate
|
|
16
16
|
from backoff._jitter import full_jitter, random_jitter
|
|
17
17
|
from backoff._wait_gen import constant, expo, fibo, runtime, decay
|
|
18
18
|
|
|
19
19
|
__all__ = [
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
20
|
+
"on_predicate",
|
|
21
|
+
"on_exception",
|
|
22
|
+
"constant",
|
|
23
|
+
"expo",
|
|
24
|
+
"decay",
|
|
25
|
+
"fibo",
|
|
26
|
+
"runtime",
|
|
27
|
+
"full_jitter",
|
|
28
|
+
"random_jitter",
|
|
29
29
|
]
|
|
30
30
|
|
|
31
|
-
__version__ = "2.
|
|
31
|
+
__version__ = "2.3.1"
|