# Table of Contents - [Tenacity — Tenacity documentation](#tenacity-tenacity-documentation) - [Tenacity — Tenacity documentation](#tenacity-tenacity-documentation) - [Tenacity — Tenacity documentation](#tenacity-tenacity-documentation) - [Changelog — Tenacity documentation](#changelog-tenacity-documentation) - [API Reference — Tenacity documentation](#api-reference-tenacity-documentation) - [Changelog — Tenacity documentation](#changelog-tenacity-documentation) - [API Reference — Tenacity documentation](#api-reference-tenacity-documentation) - [ Page not found - Read the Docs Community ](#-page-not-found-read-the-docs-community-) - [ Page not found - Read the Docs Community ](#-page-not-found-read-the-docs-community-) --- # Tenacity — Tenacity documentation * [Docs](https://tenacity.readthedocs.io/#) » * Tenacity * [Edit on GitHub](https://github.com/jd/tenacity/blob/master/doc/source/index.rst) * * * Tenacity[¶](https://tenacity.readthedocs.io/#tenacity "Permalink to this headline") ==================================================================================== [![https://img.shields.io/pypi/v/tenacity.svg](https://img.shields.io/pypi/v/tenacity.svg)](https://pypi.python.org/pypi/tenacity) [![https://circleci.com/gh/jd/tenacity.svg?style=svg](https://circleci.com/gh/jd/tenacity.svg?style=svg)](https://circleci.com/gh/jd/tenacity) [![Mergify Status](https://img.shields.io/endpoint.svg?url=https://api.mergify.com/badges/jd/tenacity&style=flat)](https://mergify.io/) **Please refer to the** [tenacity documentation](https://tenacity.readthedocs.io/en/latest/) **for a better experience.** Tenacity is an Apache 2.0 licensed general-purpose retrying library, written in Python, to simplify the task of adding retry behavior to just about anything. It originates from [a fork of retrying](https://github.com/rholder/retrying/issues/65) which is sadly no longer [maintained](https://julien.danjou.info/python-tenacity/) . Tenacity isn’t api compatible with retrying but adds significant new functionality and fixes a number of longstanding bugs. The simplest use case is retrying a flaky function whenever an Exception occurs until a value is returned. import random from tenacity import retry @retry def do\_something\_unreliable(): if random.randint(0, 10) \> 1: raise IOError("Broken sauce, everything is hosed!!!111one") else: return "Awesome sauce!" print(do\_something\_unreliable()) Features[¶](https://tenacity.readthedocs.io/#features "Permalink to this headline") ------------------------------------------------------------------------------------ * Generic Decorator API * Specify stop condition (i.e. limit by number of attempts) * Specify wait condition (i.e. exponential backoff sleeping between attempts) * Customize retrying on Exceptions * Customize retrying on expected returned result * Retry on coroutines * Retry code block with context manager Installation[¶](https://tenacity.readthedocs.io/#installation "Permalink to this headline") -------------------------------------------------------------------------------------------- To install _tenacity_, simply: $ pip install tenacity Examples[¶](https://tenacity.readthedocs.io/#examples "Permalink to this headline") ------------------------------------------------------------------------------------ ### Basic Retry[¶](https://tenacity.readthedocs.io/#basic-retry "Permalink to this headline") As you saw above, the default behavior is to retry forever without waiting when an exception is raised. @retry def never\_gonna\_give\_you\_up(): print("Retry forever ignoring Exceptions, don't wait between retries") raise Exception ### Stopping[¶](https://tenacity.readthedocs.io/#stopping "Permalink to this headline") Let’s be a little less persistent and set some boundaries, such as the number of attempts before giving up. @retry(stop\=stop\_after\_attempt(7)) def stop\_after\_7\_attempts(): print("Stopping after 7 attempts") raise Exception We don’t have all day, so let’s set a boundary for how long we should be retrying stuff. @retry(stop\=stop\_after\_delay(10)) def stop\_after\_10\_s(): print("Stopping after 10 seconds") raise Exception You can combine several stop conditions by using the | operator: @retry(stop\=(stop\_after\_delay(10) | stop\_after\_attempt(5))) def stop\_after\_10\_s\_or\_5\_retries(): print("Stopping after 10 seconds or 5 retries") raise Exception ### Waiting before retrying[¶](https://tenacity.readthedocs.io/#waiting-before-retrying "Permalink to this headline") Most things don’t like to be polled as fast as possible, so let’s just wait 2 seconds between retries. @retry(wait\=wait\_fixed(2)) def wait\_2\_s(): print("Wait 2 second between retries") raise Exception Some things perform best with a bit of randomness injected. @retry(wait\=wait\_random(min\=1, max\=2)) def wait\_random\_1\_to\_2\_s(): print("Randomly wait 1 to 2 seconds between retries") raise Exception Then again, it’s hard to beat exponential backoff when retrying distributed services and other remote endpoints. @retry(wait\=wait\_exponential(multiplier\=1, min\=4, max\=10)) def wait\_exponential\_1(): print("Wait 2^x \* 1 second between each retry starting with 4 seconds, then up to 10 seconds, then 10 seconds afterwards") raise Exception Then again, it’s also hard to beat combining fixed waits and jitter (to help avoid thundering herds) when retrying distributed services and other remote endpoints. @retry(wait\=wait\_fixed(3) + wait\_random(0, 2)) def wait\_fixed\_jitter(): print("Wait at least 3 seconds, and add up to 2 seconds of random delay") raise Exception When multiple processes are in contention for a shared resource, exponentially increasing jitter helps minimise collisions. @retry(wait\=wait\_random\_exponential(multiplier\=1, max\=60)) def wait\_exponential\_jitter(): print("Randomly wait up to 2^x \* 1 seconds between each retry until the range reaches 60 seconds, then randomly up to 60 seconds afterwards") raise Exception Sometimes it’s necessary to build a chain of backoffs. @retry(wait\=wait\_chain(\*\[wait\_fixed(3) for i in range(3)\] + \[wait\_fixed(7) for i in range(2)\] + \[wait\_fixed(9)\])) def wait\_fixed\_chained(): print("Wait 3s for 3 attempts, 7s for the next 2 attempts and 9s for all attempts thereafter") raise Exception ### Whether to retry[¶](https://tenacity.readthedocs.io/#whether-to-retry "Permalink to this headline") We have a few options for dealing with retries that raise specific or general exceptions, as in the cases here. class ClientError(Exception): """Some type of client error.""" @retry(retry\=retry\_if\_exception\_type(IOError)) def might\_io\_error(): print("Retry forever with no wait if an IOError occurs, raise any other errors") raise Exception @retry(retry\=retry\_if\_not\_exception\_type(ClientError)) def might\_client\_error(): print("Retry forever with no wait if any error other than ClientError occurs. Immediately raise ClientError.") raise Exception We can also use the result of the function to alter the behavior of retrying. def is\_none\_p(value): """Return True if value is None""" return value is None @retry(retry\=retry\_if\_result(is\_none\_p)) def might\_return\_none(): print("Retry with no wait if return value is None") See also these methods: retry\_if\_exception retry\_if\_exception\_type retry\_if\_not\_exception\_type retry\_unless\_exception\_type retry\_if\_result retry\_if\_not\_result retry\_if\_exception\_message retry\_if\_not\_exception\_message retry\_any retry\_all We can also combine several conditions: def is\_none\_p(value): """Return True if value is None""" return value is None @retry(retry\=(retry\_if\_result(is\_none\_p) | retry\_if\_exception\_type())) def might\_return\_none(): print("Retry forever ignoring Exceptions with no wait if return value is None") Any combination of stop, wait, etc. is also supported to give you the freedom to mix and match. It’s also possible to retry explicitly at any time by raising the TryAgain exception: @retry def do\_something(): result \= something\_else() if result \== 23: raise TryAgain ### Error Handling[¶](https://tenacity.readthedocs.io/#error-handling "Permalink to this headline") Normally when your function fails its final time (and will not be retried again based on your settings), a RetryError is raised. The exception your code encountered will be shown somewhere in the _middle_ of the stack trace. If you would rather see the exception your code encountered at the _end_ of the stack trace (where it is most visible), you can set reraise=True. @retry(reraise\=True, stop\=stop\_after\_attempt(3)) def raise\_my\_exception(): raise MyException("Fail") try: raise\_my\_exception() except MyException: \# timed out retrying pass ### Before and After Retry, and Logging[¶](https://tenacity.readthedocs.io/#before-and-after-retry-and-logging "Permalink to this headline") It’s possible to execute an action before any attempt of calling the function by using the before callback function: import logging import sys logging.basicConfig(stream\=sys.stderr, level\=logging.DEBUG) logger \= logging.getLogger(\_\_name\_\_) @retry(stop\=stop\_after\_attempt(3), before\=before\_log(logger, logging.DEBUG)) def raise\_my\_exception(): raise MyException("Fail") In the same spirit, It’s possible to execute after a call that failed: import logging import sys logging.basicConfig(stream\=sys.stderr, level\=logging.DEBUG) logger \= logging.getLogger(\_\_name\_\_) @retry(stop\=stop\_after\_attempt(3), after\=after\_log(logger, logging.DEBUG)) def raise\_my\_exception(): raise MyException("Fail") It’s also possible to only log failures that are going to be retried. Normally retries happen after a wait interval, so the keyword argument is called `before_sleep`: import logging import sys logging.basicConfig(stream\=sys.stderr, level\=logging.DEBUG) logger \= logging.getLogger(\_\_name\_\_) @retry(stop\=stop\_after\_attempt(3), before\_sleep\=before\_sleep\_log(logger, logging.DEBUG)) def raise\_my\_exception(): raise MyException("Fail") ### Statistics[¶](https://tenacity.readthedocs.io/#statistics "Permalink to this headline") You can access the statistics about the retry made over a function by using the retry attribute attached to the function and its statistics attribute: @retry(stop\=stop\_after\_attempt(3)) def raise\_my\_exception(): raise MyException("Fail") try: raise\_my\_exception() except Exception: pass print(raise\_my\_exception.retry.statistics) ### Custom Callbacks[¶](https://tenacity.readthedocs.io/#custom-callbacks "Permalink to this headline") You can also define your own callbacks. The callback should accept one parameter called `retry_state` that contains all information about current retry invocation. For example, you can call a custom callback function after all retries failed, without raising an exception (or you can re-raise or do anything really) def return\_last\_value(retry\_state): """return the result of the last call attempt""" return retry\_state.outcome.result() def is\_false(value): """Return True if value is False""" return value is False \# will return False after trying 3 times to get a different result @retry(stop\=stop\_after\_attempt(3), retry\_error\_callback\=return\_last\_value, retry\=retry\_if\_result(is\_false)) def eventually\_return\_false(): return False ### RetryCallState[¶](https://tenacity.readthedocs.io/#retrycallstate "Permalink to this headline") `retry_state` argument is an object of RetryCallState class: _class_ `tenacity.``RetryCallState`(_retry\_object: tenacity.BaseRetrying, fn: Optional\[WrappedFn\], args: Any, kwargs: Any_)[¶](https://tenacity.readthedocs.io/#tenacity.RetryCallState "Permalink to this definition") State related to a single call wrapped with Retrying. Constant attributes: Variable attributes: ### Other Custom Callbacks[¶](https://tenacity.readthedocs.io/#other-custom-callbacks "Permalink to this headline") It’s also possible to define custom callbacks for other keyword arguments. `my_stop`(_retry\_state_)[¶](https://tenacity.readthedocs.io/#my_stop "Permalink to this definition") | | | | --- | --- | | Parameters: | **retry\_state** (_RetryState_) – info about current retry invocation | | Returns: | whether or not retrying should stop | | Return type: | bool | `my_wait`(_retry\_state_)[¶](https://tenacity.readthedocs.io/#my_wait "Permalink to this definition") | | | | --- | --- | | Parameters: | **retry\_state** (_RetryState_) – info about current retry invocation | | Returns: | number of seconds to wait before next retry | | Return type: | float | `my_retry`(_retry\_state_)[¶](https://tenacity.readthedocs.io/#my_retry "Permalink to this definition") | | | | --- | --- | | Parameters: | **retry\_state** (_RetryState_) – info about current retry invocation | | Returns: | whether or not retrying should continue | | Return type: | bool | `my_before`(_retry\_state_)[¶](https://tenacity.readthedocs.io/#my_before "Permalink to this definition") | | | | --- | --- | | Parameters: | **retry\_state** (_RetryState_) – info about current retry invocation | `my_after`(_retry\_state_)[¶](https://tenacity.readthedocs.io/#my_after "Permalink to this definition") | | | | --- | --- | | Parameters: | **retry\_state** (_RetryState_) – info about current retry invocation | `my_before_sleep`(_retry\_state_)[¶](https://tenacity.readthedocs.io/#my_before_sleep "Permalink to this definition") | | | | --- | --- | | Parameters: | **retry\_state** (_RetryState_) – info about current retry invocation | Here’s an example with a custom `before_sleep` function: import logging logging.basicConfig(stream\=sys.stderr, level\=logging.DEBUG) logger \= logging.getLogger(\_\_name\_\_) def my\_before\_sleep(retry\_state): if retry\_state.attempt\_number < 1: loglevel \= logging.INFO else: loglevel \= logging.WARNING logger.log( loglevel, 'Retrying %s: attempt %s ended with: %s', retry\_state.fn, retry\_state.attempt\_number, retry\_state.outcome) @retry(stop\=stop\_after\_attempt(3), before\_sleep\=my\_before\_sleep) def raise\_my\_exception(): raise MyException("Fail") try: raise\_my\_exception() except RetryError: pass ### Changing Arguments at Run Time[¶](https://tenacity.readthedocs.io/#changing-arguments-at-run-time "Permalink to this headline") You can change the arguments of a retry decorator as needed when calling it by using the retry\_with function attached to the wrapped function: @retry(stop\=stop\_after\_attempt(3)) def raise\_my\_exception(): raise MyException("Fail") try: raise\_my\_exception.retry\_with(stop\=stop\_after\_attempt(4))() except Exception: pass print(raise\_my\_exception.retry.statistics) If you want to use variables to set up the retry parameters, you don’t have to use the retry decorator - you can instead use Retrying directly: def never\_good\_enough(arg1): raise Exception('Invalid argument: {}'.format(arg1)) def try\_never\_good\_enough(max\_attempts\=3): retryer \= Retrying(stop\=stop\_after\_attempt(max\_attempts), reraise\=True) retryer(never\_good\_enough, 'I really do try') ### Retrying code block[¶](https://tenacity.readthedocs.io/#retrying-code-block "Permalink to this headline") Tenacity allows you to retry a code block without the need to wraps it in an isolated function. This makes it easy to isolate failing block while sharing context. The trick is to combine a for loop and a context manager. from tenacity import Retrying, RetryError, stop\_after\_attempt try: for attempt in Retrying(stop\=stop\_after\_attempt(3)): with attempt: raise Exception('My code is failing!') except RetryError: pass You can configure every details of retry policy by configuring the Retrying object. With async code you can use AsyncRetrying. from tenacity import AsyncRetrying, RetryError, stop\_after\_attempt async def function(): try: async for attempt in AsyncRetrying(stop\=stop\_after\_attempt(3)): with attempt: raise Exception('My code is failing!') except RetryError: pass In both cases, you may want to set the result to the attempt so it’s available in retry strategies like `retry_if_result`. This can be done accessing the `retry_state` property: from tenacity import AsyncRetrying, retry\_if\_result async def function(): async for attempt in AsyncRetrying(retry\=retry\_if\_result(lambda x: x < 3)): with attempt: result \= 1 \# Some complex calculation, function call, etc. if not attempt.retry\_state.outcome.failed: attempt.retry\_state.set\_result(result) return result ### Async and retry[¶](https://tenacity.readthedocs.io/#async-and-retry "Permalink to this headline") Finally, `retry` works also on asyncio and Tornado (>= 4.5) coroutines. Sleeps are done asynchronously too. @retry async def my\_async\_function(loop): await loop.getaddrinfo('8.8.8.8', 53) @retry @tornado.gen.coroutine def my\_async\_function(http\_client, url): yield http\_client.fetch(url) You can even use alternative event loops such as curio or Trio by passing the correct sleep function: @retry(sleep\=trio.sleep) async def my\_async\_function(loop): await asks.get('https://example.org') Contribute[¶](https://tenacity.readthedocs.io/#contribute "Permalink to this headline") ---------------------------------------------------------------------------------------- 1. Check for open issues or open a fresh issue to start a discussion around a feature idea or a bug. 2. Fork [the repository](https://github.com/jd/tenacity) on GitHub to start making your changes to the **main** branch (or branch off of it). 3. Write a test which shows that the bug was fixed or that the feature works as expected. 4. Add a [changelog](https://tenacity.readthedocs.io/#Changelogs) 5. Make the docs better (or more detailed, or more easier to read, or …) ### Changelogs[¶](https://tenacity.readthedocs.io/#changelogs "Permalink to this headline") [reno](https://docs.openstack.org/reno/latest/user/usage.html) is used for managing changelogs. Take a look at their usage docs. The doc generation will automatically compile the changelogs. You just need to add them. \# Opens a template file in an editor tox \-e reno \-- new some-slug-for-my-change \--edit --- # Tenacity — Tenacity documentation * [Docs](https://tenacity.readthedocs.io/en/latest/#) » * Tenacity * [Edit on GitHub](https://github.com/jd/tenacity/blob/master/doc/source/index.rst) * * * Tenacity[¶](https://tenacity.readthedocs.io/en/latest/#tenacity "Permalink to this headline") ============================================================================================== [![https://img.shields.io/pypi/v/tenacity.svg](https://img.shields.io/pypi/v/tenacity.svg)](https://pypi.python.org/pypi/tenacity) [![https://circleci.com/gh/jd/tenacity.svg?style=svg](https://circleci.com/gh/jd/tenacity.svg?style=svg)](https://circleci.com/gh/jd/tenacity) [![Mergify Status](https://img.shields.io/endpoint.svg?url=https://api.mergify.com/badges/jd/tenacity&style=flat)](https://mergify.io/) **Please refer to the** [tenacity documentation](https://tenacity.readthedocs.io/en/latest/) **for a better experience.** Tenacity is an Apache 2.0 licensed general-purpose retrying library, written in Python, to simplify the task of adding retry behavior to just about anything. It originates from [a fork of retrying](https://github.com/rholder/retrying/issues/65) which is sadly no longer [maintained](https://julien.danjou.info/python-tenacity/) . Tenacity isn’t api compatible with retrying but adds significant new functionality and fixes a number of longstanding bugs. The simplest use case is retrying a flaky function whenever an Exception occurs until a value is returned. import random from tenacity import retry @retry def do\_something\_unreliable(): if random.randint(0, 10) \> 1: raise IOError("Broken sauce, everything is hosed!!!111one") else: return "Awesome sauce!" print(do\_something\_unreliable()) Features[¶](https://tenacity.readthedocs.io/en/latest/#features "Permalink to this headline") ---------------------------------------------------------------------------------------------- * Generic Decorator API * Specify stop condition (i.e. limit by number of attempts) * Specify wait condition (i.e. exponential backoff sleeping between attempts) * Customize retrying on Exceptions * Customize retrying on expected returned result * Retry on coroutines * Retry code block with context manager Installation[¶](https://tenacity.readthedocs.io/en/latest/#installation "Permalink to this headline") ------------------------------------------------------------------------------------------------------ To install _tenacity_, simply: $ pip install tenacity Examples[¶](https://tenacity.readthedocs.io/en/latest/#examples "Permalink to this headline") ---------------------------------------------------------------------------------------------- ### Basic Retry[¶](https://tenacity.readthedocs.io/en/latest/#basic-retry "Permalink to this headline") As you saw above, the default behavior is to retry forever without waiting when an exception is raised. @retry def never\_gonna\_give\_you\_up(): print("Retry forever ignoring Exceptions, don't wait between retries") raise Exception ### Stopping[¶](https://tenacity.readthedocs.io/en/latest/#stopping "Permalink to this headline") Let’s be a little less persistent and set some boundaries, such as the number of attempts before giving up. @retry(stop\=stop\_after\_attempt(7)) def stop\_after\_7\_attempts(): print("Stopping after 7 attempts") raise Exception We don’t have all day, so let’s set a boundary for how long we should be retrying stuff. @retry(stop\=stop\_after\_delay(10)) def stop\_after\_10\_s(): print("Stopping after 10 seconds") raise Exception You can combine several stop conditions by using the | operator: @retry(stop\=(stop\_after\_delay(10) | stop\_after\_attempt(5))) def stop\_after\_10\_s\_or\_5\_retries(): print("Stopping after 10 seconds or 5 retries") raise Exception ### Waiting before retrying[¶](https://tenacity.readthedocs.io/en/latest/#waiting-before-retrying "Permalink to this headline") Most things don’t like to be polled as fast as possible, so let’s just wait 2 seconds between retries. @retry(wait\=wait\_fixed(2)) def wait\_2\_s(): print("Wait 2 second between retries") raise Exception Some things perform best with a bit of randomness injected. @retry(wait\=wait\_random(min\=1, max\=2)) def wait\_random\_1\_to\_2\_s(): print("Randomly wait 1 to 2 seconds between retries") raise Exception Then again, it’s hard to beat exponential backoff when retrying distributed services and other remote endpoints. @retry(wait\=wait\_exponential(multiplier\=1, min\=4, max\=10)) def wait\_exponential\_1(): print("Wait 2^x \* 1 second between each retry starting with 4 seconds, then up to 10 seconds, then 10 seconds afterwards") raise Exception Then again, it’s also hard to beat combining fixed waits and jitter (to help avoid thundering herds) when retrying distributed services and other remote endpoints. @retry(wait\=wait\_fixed(3) + wait\_random(0, 2)) def wait\_fixed\_jitter(): print("Wait at least 3 seconds, and add up to 2 seconds of random delay") raise Exception When multiple processes are in contention for a shared resource, exponentially increasing jitter helps minimise collisions. @retry(wait\=wait\_random\_exponential(multiplier\=1, max\=60)) def wait\_exponential\_jitter(): print("Randomly wait up to 2^x \* 1 seconds between each retry until the range reaches 60 seconds, then randomly up to 60 seconds afterwards") raise Exception Sometimes it’s necessary to build a chain of backoffs. @retry(wait\=wait\_chain(\*\[wait\_fixed(3) for i in range(3)\] + \[wait\_fixed(7) for i in range(2)\] + \[wait\_fixed(9)\])) def wait\_fixed\_chained(): print("Wait 3s for 3 attempts, 7s for the next 2 attempts and 9s for all attempts thereafter") raise Exception ### Whether to retry[¶](https://tenacity.readthedocs.io/en/latest/#whether-to-retry "Permalink to this headline") We have a few options for dealing with retries that raise specific or general exceptions, as in the cases here. class ClientError(Exception): """Some type of client error.""" @retry(retry\=retry\_if\_exception\_type(IOError)) def might\_io\_error(): print("Retry forever with no wait if an IOError occurs, raise any other errors") raise Exception @retry(retry\=retry\_if\_not\_exception\_type(ClientError)) def might\_client\_error(): print("Retry forever with no wait if any error other than ClientError occurs. Immediately raise ClientError.") raise Exception We can also use the result of the function to alter the behavior of retrying. def is\_none\_p(value): """Return True if value is None""" return value is None @retry(retry\=retry\_if\_result(is\_none\_p)) def might\_return\_none(): print("Retry with no wait if return value is None") See also these methods: retry\_if\_exception retry\_if\_exception\_type retry\_if\_not\_exception\_type retry\_unless\_exception\_type retry\_if\_result retry\_if\_not\_result retry\_if\_exception\_message retry\_if\_not\_exception\_message retry\_any retry\_all We can also combine several conditions: def is\_none\_p(value): """Return True if value is None""" return value is None @retry(retry\=(retry\_if\_result(is\_none\_p) | retry\_if\_exception\_type())) def might\_return\_none(): print("Retry forever ignoring Exceptions with no wait if return value is None") Any combination of stop, wait, etc. is also supported to give you the freedom to mix and match. It’s also possible to retry explicitly at any time by raising the TryAgain exception: @retry def do\_something(): result \= something\_else() if result \== 23: raise TryAgain ### Error Handling[¶](https://tenacity.readthedocs.io/en/latest/#error-handling "Permalink to this headline") Normally when your function fails its final time (and will not be retried again based on your settings), a RetryError is raised. The exception your code encountered will be shown somewhere in the _middle_ of the stack trace. If you would rather see the exception your code encountered at the _end_ of the stack trace (where it is most visible), you can set reraise=True. @retry(reraise\=True, stop\=stop\_after\_attempt(3)) def raise\_my\_exception(): raise MyException("Fail") try: raise\_my\_exception() except MyException: \# timed out retrying pass ### Before and After Retry, and Logging[¶](https://tenacity.readthedocs.io/en/latest/#before-and-after-retry-and-logging "Permalink to this headline") It’s possible to execute an action before any attempt of calling the function by using the before callback function: import logging import sys logging.basicConfig(stream\=sys.stderr, level\=logging.DEBUG) logger \= logging.getLogger(\_\_name\_\_) @retry(stop\=stop\_after\_attempt(3), before\=before\_log(logger, logging.DEBUG)) def raise\_my\_exception(): raise MyException("Fail") In the same spirit, It’s possible to execute after a call that failed: import logging import sys logging.basicConfig(stream\=sys.stderr, level\=logging.DEBUG) logger \= logging.getLogger(\_\_name\_\_) @retry(stop\=stop\_after\_attempt(3), after\=after\_log(logger, logging.DEBUG)) def raise\_my\_exception(): raise MyException("Fail") It’s also possible to only log failures that are going to be retried. Normally retries happen after a wait interval, so the keyword argument is called `before_sleep`: import logging import sys logging.basicConfig(stream\=sys.stderr, level\=logging.DEBUG) logger \= logging.getLogger(\_\_name\_\_) @retry(stop\=stop\_after\_attempt(3), before\_sleep\=before\_sleep\_log(logger, logging.DEBUG)) def raise\_my\_exception(): raise MyException("Fail") ### Statistics[¶](https://tenacity.readthedocs.io/en/latest/#statistics "Permalink to this headline") You can access the statistics about the retry made over a function by using the retry attribute attached to the function and its statistics attribute: @retry(stop\=stop\_after\_attempt(3)) def raise\_my\_exception(): raise MyException("Fail") try: raise\_my\_exception() except Exception: pass print(raise\_my\_exception.retry.statistics) ### Custom Callbacks[¶](https://tenacity.readthedocs.io/en/latest/#custom-callbacks "Permalink to this headline") You can also define your own callbacks. The callback should accept one parameter called `retry_state` that contains all information about current retry invocation. For example, you can call a custom callback function after all retries failed, without raising an exception (or you can re-raise or do anything really) def return\_last\_value(retry\_state): """return the result of the last call attempt""" return retry\_state.outcome.result() def is\_false(value): """Return True if value is False""" return value is False \# will return False after trying 3 times to get a different result @retry(stop\=stop\_after\_attempt(3), retry\_error\_callback\=return\_last\_value, retry\=retry\_if\_result(is\_false)) def eventually\_return\_false(): return False ### RetryCallState[¶](https://tenacity.readthedocs.io/en/latest/#retrycallstate "Permalink to this headline") `retry_state` argument is an object of RetryCallState class: _class_ `tenacity.``RetryCallState`(_retry\_object: tenacity.BaseRetrying, fn: Optional\[WrappedFn\], args: Any, kwargs: Any_)[¶](https://tenacity.readthedocs.io/en/latest/#tenacity.RetryCallState "Permalink to this definition") State related to a single call wrapped with Retrying. Constant attributes: Variable attributes: ### Other Custom Callbacks[¶](https://tenacity.readthedocs.io/en/latest/#other-custom-callbacks "Permalink to this headline") It’s also possible to define custom callbacks for other keyword arguments. `my_stop`(_retry\_state_)[¶](https://tenacity.readthedocs.io/en/latest/#my_stop "Permalink to this definition") | | | | --- | --- | | Parameters: | **retry\_state** (_RetryState_) – info about current retry invocation | | Returns: | whether or not retrying should stop | | Return type: | bool | `my_wait`(_retry\_state_)[¶](https://tenacity.readthedocs.io/en/latest/#my_wait "Permalink to this definition") | | | | --- | --- | | Parameters: | **retry\_state** (_RetryState_) – info about current retry invocation | | Returns: | number of seconds to wait before next retry | | Return type: | float | `my_retry`(_retry\_state_)[¶](https://tenacity.readthedocs.io/en/latest/#my_retry "Permalink to this definition") | | | | --- | --- | | Parameters: | **retry\_state** (_RetryState_) – info about current retry invocation | | Returns: | whether or not retrying should continue | | Return type: | bool | `my_before`(_retry\_state_)[¶](https://tenacity.readthedocs.io/en/latest/#my_before "Permalink to this definition") | | | | --- | --- | | Parameters: | **retry\_state** (_RetryState_) – info about current retry invocation | `my_after`(_retry\_state_)[¶](https://tenacity.readthedocs.io/en/latest/#my_after "Permalink to this definition") | | | | --- | --- | | Parameters: | **retry\_state** (_RetryState_) – info about current retry invocation | `my_before_sleep`(_retry\_state_)[¶](https://tenacity.readthedocs.io/en/latest/#my_before_sleep "Permalink to this definition") | | | | --- | --- | | Parameters: | **retry\_state** (_RetryState_) – info about current retry invocation | Here’s an example with a custom `before_sleep` function: import logging logging.basicConfig(stream\=sys.stderr, level\=logging.DEBUG) logger \= logging.getLogger(\_\_name\_\_) def my\_before\_sleep(retry\_state): if retry\_state.attempt\_number < 1: loglevel \= logging.INFO else: loglevel \= logging.WARNING logger.log( loglevel, 'Retrying %s: attempt %s ended with: %s', retry\_state.fn, retry\_state.attempt\_number, retry\_state.outcome) @retry(stop\=stop\_after\_attempt(3), before\_sleep\=my\_before\_sleep) def raise\_my\_exception(): raise MyException("Fail") try: raise\_my\_exception() except RetryError: pass ### Changing Arguments at Run Time[¶](https://tenacity.readthedocs.io/en/latest/#changing-arguments-at-run-time "Permalink to this headline") You can change the arguments of a retry decorator as needed when calling it by using the retry\_with function attached to the wrapped function: @retry(stop\=stop\_after\_attempt(3)) def raise\_my\_exception(): raise MyException("Fail") try: raise\_my\_exception.retry\_with(stop\=stop\_after\_attempt(4))() except Exception: pass print(raise\_my\_exception.retry.statistics) If you want to use variables to set up the retry parameters, you don’t have to use the retry decorator - you can instead use Retrying directly: def never\_good\_enough(arg1): raise Exception('Invalid argument: {}'.format(arg1)) def try\_never\_good\_enough(max\_attempts\=3): retryer \= Retrying(stop\=stop\_after\_attempt(max\_attempts), reraise\=True) retryer(never\_good\_enough, 'I really do try') ### Retrying code block[¶](https://tenacity.readthedocs.io/en/latest/#retrying-code-block "Permalink to this headline") Tenacity allows you to retry a code block without the need to wraps it in an isolated function. This makes it easy to isolate failing block while sharing context. The trick is to combine a for loop and a context manager. from tenacity import Retrying, RetryError, stop\_after\_attempt try: for attempt in Retrying(stop\=stop\_after\_attempt(3)): with attempt: raise Exception('My code is failing!') except RetryError: pass You can configure every details of retry policy by configuring the Retrying object. With async code you can use AsyncRetrying. from tenacity import AsyncRetrying, RetryError, stop\_after\_attempt async def function(): try: async for attempt in AsyncRetrying(stop\=stop\_after\_attempt(3)): with attempt: raise Exception('My code is failing!') except RetryError: pass In both cases, you may want to set the result to the attempt so it’s available in retry strategies like `retry_if_result`. This can be done accessing the `retry_state` property: from tenacity import AsyncRetrying, retry\_if\_result async def function(): async for attempt in AsyncRetrying(retry\=retry\_if\_result(lambda x: x < 3)): with attempt: result \= 1 \# Some complex calculation, function call, etc. if not attempt.retry\_state.outcome.failed: attempt.retry\_state.set\_result(result) return result ### Async and retry[¶](https://tenacity.readthedocs.io/en/latest/#async-and-retry "Permalink to this headline") Finally, `retry` works also on asyncio and Tornado (>= 4.5) coroutines. Sleeps are done asynchronously too. @retry async def my\_async\_function(loop): await loop.getaddrinfo('8.8.8.8', 53) @retry @tornado.gen.coroutine def my\_async\_function(http\_client, url): yield http\_client.fetch(url) You can even use alternative event loops such as curio or Trio by passing the correct sleep function: @retry(sleep\=trio.sleep) async def my\_async\_function(loop): await asks.get('https://example.org') Contribute[¶](https://tenacity.readthedocs.io/en/latest/#contribute "Permalink to this headline") -------------------------------------------------------------------------------------------------- 1. Check for open issues or open a fresh issue to start a discussion around a feature idea or a bug. 2. Fork [the repository](https://github.com/jd/tenacity) on GitHub to start making your changes to the **main** branch (or branch off of it). 3. Write a test which shows that the bug was fixed or that the feature works as expected. 4. Add a [changelog](https://tenacity.readthedocs.io/en/latest/#Changelogs) 5. Make the docs better (or more detailed, or more easier to read, or …) ### Changelogs[¶](https://tenacity.readthedocs.io/en/latest/#changelogs "Permalink to this headline") [reno](https://docs.openstack.org/reno/latest/user/usage.html) is used for managing changelogs. Take a look at their usage docs. The doc generation will automatically compile the changelogs. You just need to add them. \# Opens a template file in an editor tox \-e reno \-- new some-slug-for-my-change \--edit --- # Tenacity — Tenacity documentation * [Docs](https://tenacity.readthedocs.io/en/stable/#) » * Tenacity * [Edit on GitHub](https://github.com/jd/tenacity/blob/548c5d490187af6f339cbffdd0add38aecc3ecb0/doc/source/index.rst) * * * Tenacity[¶](https://tenacity.readthedocs.io/en/stable/#tenacity "Permalink to this heading") ============================================================================================= [![https://img.shields.io/pypi/v/tenacity.svg](https://img.shields.io/pypi/v/tenacity.svg)](https://pypi.python.org/pypi/tenacity) [![https://circleci.com/gh/jd/tenacity.svg?style=svg](https://circleci.com/gh/jd/tenacity.svg?style=svg)](https://circleci.com/gh/jd/tenacity) [![Mergify Status](https://img.shields.io/endpoint.svg?url=https://api.mergify.com/badges/jd/tenacity&style=flat)](https://mergify.io/) Tenacity is an Apache 2.0 licensed general-purpose retrying library, written in Python, to simplify the task of adding retry behavior to just about anything. It originates from [a fork of retrying](https://github.com/rholder/retrying/issues/65) which is sadly no longer [maintained](https://julien.danjou.info/python-tenacity/) . Tenacity isn’t api compatible with retrying but adds significant new functionality and fixes a number of longstanding bugs. The simplest use case is retrying a flaky function whenever an Exception occurs until a value is returned. import random from tenacity import retry @retry def do\_something\_unreliable(): if random.randint(0, 10) \> 1: raise IOError("Broken sauce, everything is hosed!!!111one") else: return "Awesome sauce!" print(do\_something\_unreliable()) Features[¶](https://tenacity.readthedocs.io/en/stable/#features "Permalink to this heading") --------------------------------------------------------------------------------------------- * Generic Decorator API * Specify stop condition (i.e. limit by number of attempts) * Specify wait condition (i.e. exponential backoff sleeping between attempts) * Customize retrying on Exceptions * Customize retrying on expected returned result * Retry on coroutines * Retry code block with context manager Installation[¶](https://tenacity.readthedocs.io/en/stable/#installation "Permalink to this heading") ----------------------------------------------------------------------------------------------------- To install _tenacity_, simply: $ pip install tenacity Examples[¶](https://tenacity.readthedocs.io/en/stable/#examples "Permalink to this heading") --------------------------------------------------------------------------------------------- ### Basic Retry[¶](https://tenacity.readthedocs.io/en/stable/#basic-retry "Permalink to this heading") As you saw above, the default behavior is to retry forever without waiting when an exception is raised. @retry def never\_gonna\_give\_you\_up(): print("Retry forever ignoring Exceptions, don't wait between retries") raise Exception ### Stopping[¶](https://tenacity.readthedocs.io/en/stable/#stopping "Permalink to this heading") Let’s be a little less persistent and set some boundaries, such as the number of attempts before giving up. @retry(stop\=stop\_after\_attempt(7)) def stop\_after\_7\_attempts(): print("Stopping after 7 attempts") raise Exception We don’t have all day, so let’s set a boundary for how long we should be retrying stuff. @retry(stop\=stop\_after\_delay(10)) def stop\_after\_10\_s(): print("Stopping after 10 seconds") raise Exception You can combine several stop conditions by using the | operator: @retry(stop\=(stop\_after\_delay(10) | stop\_after\_attempt(5))) def stop\_after\_10\_s\_or\_5\_retries(): print("Stopping after 10 seconds or 5 retries") raise Exception ### Waiting before retrying[¶](https://tenacity.readthedocs.io/en/stable/#waiting-before-retrying "Permalink to this heading") Most things don’t like to be polled as fast as possible, so let’s just wait 2 seconds between retries. @retry(wait\=wait\_fixed(2)) def wait\_2\_s(): print("Wait 2 second between retries") raise Exception Some things perform best with a bit of randomness injected. @retry(wait\=wait\_random(min\=1, max\=2)) def wait\_random\_1\_to\_2\_s(): print("Randomly wait 1 to 2 seconds between retries") raise Exception Then again, it’s hard to beat exponential backoff when retrying distributed services and other remote endpoints. @retry(wait\=wait\_exponential(multiplier\=1, min\=4, max\=10)) def wait\_exponential\_1(): print("Wait 2^x \* 1 second between each retry starting with 4 seconds, then up to 10 seconds, then 10 seconds afterwards") raise Exception Then again, it’s also hard to beat combining fixed waits and jitter (to help avoid thundering herds) when retrying distributed services and other remote endpoints. @retry(wait\=wait\_fixed(3) + wait\_random(0, 2)) def wait\_fixed\_jitter(): print("Wait at least 3 seconds, and add up to 2 seconds of random delay") raise Exception When multiple processes are in contention for a shared resource, exponentially increasing jitter helps minimise collisions. @retry(wait\=wait\_random\_exponential(multiplier\=1, max\=60)) def wait\_exponential\_jitter(): print("Randomly wait up to 2^x \* 1 seconds between each retry until the range reaches 60 seconds, then randomly up to 60 seconds afterwards") raise Exception Sometimes it’s necessary to build a chain of backoffs. @retry(wait\=wait\_chain(\*\[wait\_fixed(3) for i in range(3)\] + \[wait\_fixed(7) for i in range(2)\] + \[wait\_fixed(9)\])) def wait\_fixed\_chained(): print("Wait 3s for 3 attempts, 7s for the next 2 attempts and 9s for all attempts thereafter") raise Exception ### Whether to retry[¶](https://tenacity.readthedocs.io/en/stable/#whether-to-retry "Permalink to this heading") We have a few options for dealing with retries that raise specific or general exceptions, as in the cases here. class ClientError(Exception): """Some type of client error.""" @retry(retry\=retry\_if\_exception\_type(IOError)) def might\_io\_error(): print("Retry forever with no wait if an IOError occurs, raise any other errors") raise Exception @retry(retry\=retry\_if\_not\_exception\_type(ClientError)) def might\_client\_error(): print("Retry forever with no wait if any error other than ClientError occurs. Immediately raise ClientError.") raise Exception We can also use the result of the function to alter the behavior of retrying. def is\_none\_p(value): """Return True if value is None""" return value is None @retry(retry\=retry\_if\_result(is\_none\_p)) def might\_return\_none(): print("Retry with no wait if return value is None") See also these methods: retry\_if\_exception retry\_if\_exception\_type retry\_if\_not\_exception\_type retry\_unless\_exception\_type retry\_if\_result retry\_if\_not\_result retry\_if\_exception\_message retry\_if\_not\_exception\_message retry\_any retry\_all We can also combine several conditions: def is\_none\_p(value): """Return True if value is None""" return value is None @retry(retry\=(retry\_if\_result(is\_none\_p) | retry\_if\_exception\_type())) def might\_return\_none(): print("Retry forever ignoring Exceptions with no wait if return value is None") Any combination of stop, wait, etc. is also supported to give you the freedom to mix and match. It’s also possible to retry explicitly at any time by raising the TryAgain exception: @retry def do\_something(): result \= something\_else() if result \== 23: raise TryAgain ### Error Handling[¶](https://tenacity.readthedocs.io/en/stable/#error-handling "Permalink to this heading") Normally when your function fails its final time (and will not be retried again based on your settings), a RetryError is raised. The exception your code encountered will be shown somewhere in the _middle_ of the stack trace. If you would rather see the exception your code encountered at the _end_ of the stack trace (where it is most visible), you can set reraise=True. @retry(reraise\=True, stop\=stop\_after\_attempt(3)) def raise\_my\_exception(): raise MyException("Fail") try: raise\_my\_exception() except MyException: \# timed out retrying pass ### Before and After Retry, and Logging[¶](https://tenacity.readthedocs.io/en/stable/#before-and-after-retry-and-logging "Permalink to this heading") It’s possible to execute an action before any attempt of calling the function by using the before callback function: import logging import sys logging.basicConfig(stream\=sys.stderr, level\=logging.DEBUG) logger \= logging.getLogger(\_\_name\_\_) @retry(stop\=stop\_after\_attempt(3), before\=before\_log(logger, logging.DEBUG)) def raise\_my\_exception(): raise MyException("Fail") In the same spirit, It’s possible to execute after a call that failed: import logging import sys logging.basicConfig(stream\=sys.stderr, level\=logging.DEBUG) logger \= logging.getLogger(\_\_name\_\_) @retry(stop\=stop\_after\_attempt(3), after\=after\_log(logger, logging.DEBUG)) def raise\_my\_exception(): raise MyException("Fail") It’s also possible to only log failures that are going to be retried. Normally retries happen after a wait interval, so the keyword argument is called `before_sleep`: import logging import sys logging.basicConfig(stream\=sys.stderr, level\=logging.DEBUG) logger \= logging.getLogger(\_\_name\_\_) @retry(stop\=stop\_after\_attempt(3), before\_sleep\=before\_sleep\_log(logger, logging.DEBUG)) def raise\_my\_exception(): raise MyException("Fail") ### Statistics[¶](https://tenacity.readthedocs.io/en/stable/#statistics "Permalink to this heading") You can access the statistics about the retry made over a function by using the retry attribute attached to the function and its statistics attribute: @retry(stop\=stop\_after\_attempt(3)) def raise\_my\_exception(): raise MyException("Fail") try: raise\_my\_exception() except Exception: pass print(raise\_my\_exception.retry.statistics) ### Custom Callbacks[¶](https://tenacity.readthedocs.io/en/stable/#custom-callbacks "Permalink to this heading") You can also define your own callbacks. The callback should accept one parameter called `retry_state` that contains all information about current retry invocation. For example, you can call a custom callback function after all retries failed, without raising an exception (or you can re-raise or do anything really) def return\_last\_value(retry\_state): """return the result of the last call attempt""" return retry\_state.outcome.result() def is\_false(value): """Return True if value is False""" return value is False \# will return False after trying 3 times to get a different result @retry(stop\=stop\_after\_attempt(3), retry\_error\_callback\=return\_last\_value, retry\=retry\_if\_result(is\_false)) def eventually\_return\_false(): return False ### RetryCallState[¶](https://tenacity.readthedocs.io/en/stable/#retrycallstate "Permalink to this heading") `retry_state` argument is an object of RetryCallState class: _class_ tenacity.RetryCallState(_retry\_object: BaseRetrying_, _fn: Optional\[WrappedFn\]_, _args: Any_, _kwargs: Any_)[¶](https://tenacity.readthedocs.io/en/stable/#tenacity.RetryCallState "Permalink to this definition") State related to a single call wrapped with Retrying. Constant attributes: start\_time(_float_)[¶](https://tenacity.readthedocs.io/en/stable/#tenacity.RetryCallState.start_time "Permalink to this definition") Retry call start timestamp retry\_object(_BaseRetrying_)[¶](https://tenacity.readthedocs.io/en/stable/#tenacity.RetryCallState.retry_object "Permalink to this definition") Retry manager object fn(_callable_)[¶](https://tenacity.readthedocs.io/en/stable/#tenacity.RetryCallState.fn "Permalink to this definition") Function wrapped by this retry call args(_tuple_)[¶](https://tenacity.readthedocs.io/en/stable/#tenacity.RetryCallState.args "Permalink to this definition") Arguments of the function wrapped by this retry call kwargs(_dict_)[¶](https://tenacity.readthedocs.io/en/stable/#tenacity.RetryCallState.kwargs "Permalink to this definition") Keyword arguments of the function wrapped by this retry call Variable attributes: attempt\_number(_int_)[¶](https://tenacity.readthedocs.io/en/stable/#tenacity.RetryCallState.attempt_number "Permalink to this definition") The number of the current attempt outcome(_tenacity.Future or None_)[¶](https://tenacity.readthedocs.io/en/stable/#tenacity.RetryCallState.outcome "Permalink to this definition") Last outcome (result or exception) produced by the function outcome\_timestamp(_float or None_)[¶](https://tenacity.readthedocs.io/en/stable/#tenacity.RetryCallState.outcome_timestamp "Permalink to this definition") Timestamp of the last outcome idle\_for(_float_)[¶](https://tenacity.readthedocs.io/en/stable/#tenacity.RetryCallState.idle_for "Permalink to this definition") Time spent sleeping in retries next\_action(_tenacity.RetryAction or None_)[¶](https://tenacity.readthedocs.io/en/stable/#tenacity.RetryCallState.next_action "Permalink to this definition") Next action as decided by the retry manager ### Other Custom Callbacks[¶](https://tenacity.readthedocs.io/en/stable/#other-custom-callbacks "Permalink to this heading") It’s also possible to define custom callbacks for other keyword arguments. my\_stop(_retry\_state_)[¶](https://tenacity.readthedocs.io/en/stable/#my_stop "Permalink to this definition") Parameters: **retry\_state** (_RetryState_) – info about current retry invocation Returns: whether or not retrying should stop Return type: bool my\_wait(_retry\_state_)[¶](https://tenacity.readthedocs.io/en/stable/#my_wait "Permalink to this definition") Parameters: **retry\_state** (_RetryState_) – info about current retry invocation Returns: number of seconds to wait before next retry Return type: float my\_retry(_retry\_state_)[¶](https://tenacity.readthedocs.io/en/stable/#my_retry "Permalink to this definition") Parameters: **retry\_state** (_RetryState_) – info about current retry invocation Returns: whether or not retrying should continue Return type: bool my\_before(_retry\_state_)[¶](https://tenacity.readthedocs.io/en/stable/#my_before "Permalink to this definition") Parameters: **retry\_state** (_RetryState_) – info about current retry invocation my\_after(_retry\_state_)[¶](https://tenacity.readthedocs.io/en/stable/#my_after "Permalink to this definition") Parameters: **retry\_state** (_RetryState_) – info about current retry invocation my\_before\_sleep(_retry\_state_)[¶](https://tenacity.readthedocs.io/en/stable/#my_before_sleep "Permalink to this definition") Parameters: **retry\_state** (_RetryState_) – info about current retry invocation Here’s an example with a custom `before_sleep` function: import logging logging.basicConfig(stream\=sys.stderr, level\=logging.DEBUG) logger \= logging.getLogger(\_\_name\_\_) def my\_before\_sleep(retry\_state): if retry\_state.attempt\_number < 1: loglevel \= logging.INFO else: loglevel \= logging.WARNING logger.log( loglevel, 'Retrying %s: attempt %s ended with: %s', retry\_state.fn, retry\_state.attempt\_number, retry\_state.outcome) @retry(stop\=stop\_after\_attempt(3), before\_sleep\=my\_before\_sleep) def raise\_my\_exception(): raise MyException("Fail") try: raise\_my\_exception() except RetryError: pass ### Changing Arguments at Run Time[¶](https://tenacity.readthedocs.io/en/stable/#changing-arguments-at-run-time "Permalink to this heading") You can change the arguments of a retry decorator as needed when calling it by using the retry\_with function attached to the wrapped function: @retry(stop\=stop\_after\_attempt(3)) def raise\_my\_exception(): raise MyException("Fail") try: raise\_my\_exception.retry\_with(stop\=stop\_after\_attempt(4))() except Exception: pass print(raise\_my\_exception.retry.statistics) If you want to use variables to set up the retry parameters, you don’t have to use the retry decorator - you can instead use Retrying directly: def never\_good\_enough(arg1): raise Exception('Invalid argument: {}'.format(arg1)) def try\_never\_good\_enough(max\_attempts\=3): retryer \= Retrying(stop\=stop\_after\_attempt(max\_attempts), reraise\=True) retryer(never\_good\_enough, 'I really do try') ### Retrying code block[¶](https://tenacity.readthedocs.io/en/stable/#retrying-code-block "Permalink to this heading") Tenacity allows you to retry a code block without the need to wraps it in an isolated function. This makes it easy to isolate failing block while sharing context. The trick is to combine a for loop and a context manager. from tenacity import Retrying, RetryError, stop\_after\_attempt try: for attempt in Retrying(stop\=stop\_after\_attempt(3)): with attempt: raise Exception('My code is failing!') except RetryError: pass You can configure every details of retry policy by configuring the Retrying object. With async code you can use AsyncRetrying. from tenacity import AsyncRetrying, RetryError, stop\_after\_attempt async def function(): try: async for attempt in AsyncRetrying(stop\=stop\_after\_attempt(3)): with attempt: raise Exception('My code is failing!') except RetryError: pass In both cases, you may want to set the result to the attempt so it’s available in retry strategies like `retry_if_result`. This can be done accessing the `retry_state` property: from tenacity import AsyncRetrying, retry\_if\_result async def function(): async for attempt in AsyncRetrying(retry\=retry\_if\_result(lambda x: x < 3)): with attempt: result \= 1 \# Some complex calculation, function call, etc. if not attempt.retry\_state.outcome.failed: attempt.retry\_state.set\_result(result) return result ### Async and retry[¶](https://tenacity.readthedocs.io/en/stable/#async-and-retry "Permalink to this heading") Finally, `retry` works also on asyncio and Tornado (>= 4.5) coroutines. Sleeps are done asynchronously too. @retry async def my\_async\_function(loop): await loop.getaddrinfo('8.8.8.8', 53) @retry @tornado.gen.coroutine def my\_async\_function(http\_client, url): yield http\_client.fetch(url) You can even use alternative event loops such as curio or Trio by passing the correct sleep function: @retry(sleep\=trio.sleep) async def my\_async\_function(loop): await asks.get('https://example.org') Contribute[¶](https://tenacity.readthedocs.io/en/stable/#contribute "Permalink to this heading") ------------------------------------------------------------------------------------------------- 1. Check for open issues or open a fresh issue to start a discussion around a feature idea or a bug. 2. Fork [the repository](https://github.com/jd/tenacity) on GitHub to start making your changes to the **master** branch (or branch off of it). 3. Write a test which shows that the bug was fixed or that the feature works as expected. 4. Add a [changelog](https://tenacity.readthedocs.io/en/stable/#Changelogs) 5. Make the docs better (or more detailed, or more easier to read, or …) ### Changelogs[¶](https://tenacity.readthedocs.io/en/stable/#changelogs "Permalink to this heading") [reno](https://docs.openstack.org/reno/latest/user/usage.html) is used for managing changelogs. Take a look at their usage docs. The doc generation will automatically compile the changelogs. You just need to add them. \# Opens a template file in an editor tox \-e reno \-- new some-slug-for-my-change \--edit --- # Changelog — Tenacity documentation * [Docs](https://tenacity.readthedocs.io/en/latest/index.html) » * Changelog * [Edit on GitHub](https://github.com/jd/tenacity/blob/master/doc/source/changelog.rst) * * * Changelog[¶](https://tenacity.readthedocs.io/en/latest/changelog.html#changelog "Permalink to this headline") ============================================================================================================== Unreleased[¶](https://tenacity.readthedocs.io/en/latest/changelog.html#unreleased "Permalink to this headline") ---------------------------------------------------------------------------------------------------------------- ### Upgrade Notes[¶](https://tenacity.readthedocs.io/en/latest/changelog.html#upgrade-notes "Permalink to this headline") * Support for Python 3.6 has been removed. ### Bug Fixes[¶](https://tenacity.readthedocs.io/en/latest/changelog.html#bug-fixes "Permalink to this headline") * Fixes test failures with typeguard 3.x ### Other Notes[¶](https://tenacity.readthedocs.io/en/latest/changelog.html#other-notes "Permalink to this headline") * Added a link to the documentation, as code snippets are not being rendered properly Changed branch name to main in index.rst 8.2.2[¶](https://tenacity.readthedocs.io/en/latest/changelog.html#relnotes-8-2-2 "Permalink to this headline") --------------------------------------------------------------------------------------------------------------- ### Bug Fixes[¶](https://tenacity.readthedocs.io/en/latest/changelog.html#relnotes-8-2-2-bug-fixes "Permalink to this headline") * Argument wait was improperly annotated, making mypy checks fail. Now it’s annotated as typing.Union\[wait\_base, typing.Callable\[\[“RetryCallState”\], typing.Union\[float, int\]\]\] ### Other Notes[¶](https://tenacity.readthedocs.io/en/latest/changelog.html#relnotes-8-2-2-other-notes "Permalink to this headline") * Add retry\_if\_exception\_cause\_type\`and \`wait\_exponential\_jitter to \_\_all\_\_ of init.py 8.2.0[¶](https://tenacity.readthedocs.io/en/latest/changelog.html#relnotes-8-2-0 "Permalink to this headline") --------------------------------------------------------------------------------------------------------------- ### Prelude[¶](https://tenacity.readthedocs.io/en/latest/changelog.html#prelude "Permalink to this headline") Clarify usage of reraise keyword argument ### New Features[¶](https://tenacity.readthedocs.io/en/latest/changelog.html#new-features "Permalink to this headline") * Explicitly export convenience symbols from tenacity root module * * accept `datetime.timedelta` instances as argument to `tenacity.stop.stop_after_delay` ### Bug Fixes[¶](https://tenacity.readthedocs.io/en/latest/changelog.html#relnotes-8-2-0-bug-fixes "Permalink to this headline") * Fix async loop with retrying code block when result is available. * AsyncRetrying was erroneously implementing \_\_iter\_\_(), making tenacity retrying mechanism working but in a synchronous fashion and not waiting as expected. This interface has been removed, \_\_aiter\_\_() should be used instead. 8.1.0[¶](https://tenacity.readthedocs.io/en/latest/changelog.html#relnotes-8-1-0 "Permalink to this headline") --------------------------------------------------------------------------------------------------------------- ### New Features[¶](https://tenacity.readthedocs.io/en/latest/changelog.html#relnotes-8-1-0-new-features "Permalink to this headline") * Add a new retry\_base class called retry\_if\_exception\_cause\_type that checks, recursively, if any of the causes of the raised exception is of a certain type. * Add `datetime.timedelta` as accepted wait unit type. * Implement a wait.wait\_exponential\_jitter per Google’s storage retry guide. See [https://cloud.google.com/storage/docs/retry-strategy](https://cloud.google.com/storage/docs/retry-strategy) ### Bug Fixes[¶](https://tenacity.readthedocs.io/en/latest/changelog.html#relnotes-8-1-0-bug-fixes "Permalink to this headline") * Sphinx build error where Sphinx complains about an undefined class. 8.0.1[¶](https://tenacity.readthedocs.io/en/latest/changelog.html#relnotes-8-0-1 "Permalink to this headline") --------------------------------------------------------------------------------------------------------------- ### Bug Fixes[¶](https://tenacity.readthedocs.io/en/latest/changelog.html#relnotes-8-0-1-bug-fixes "Permalink to this headline") * Fix after\_log logger format: function name was used with delay formatting. 8.0.0[¶](https://tenacity.readthedocs.io/en/latest/changelog.html#relnotes-8-0-0 "Permalink to this headline") --------------------------------------------------------------------------------------------------------------- ### New Features[¶](https://tenacity.readthedocs.io/en/latest/changelog.html#relnotes-8-0-0-new-features "Permalink to this headline") * Add `retry_if_not_exception_type()` that allows to retry if a raised exception doesn’t match given exceptions. * Most part of the code is type annotated. * Python 3.10 support has been added. * Add a `__repr__` method to `RetryCallState` objects for easier debugging. ### Upgrade Notes[¶](https://tenacity.readthedocs.io/en/latest/changelog.html#relnotes-8-0-0-upgrade-notes "Permalink to this headline") * Removed BaseRetrying.call: was long time deprecated and produced DeprecationWarning * Removed BaseRetrying.fn: was noted as deprecated * API change: BaseRetrying.begin() do not require arguments anymore as it not setting BaseRetrying.fn ### Bug Fixes[¶](https://tenacity.readthedocs.io/en/latest/changelog.html#relnotes-8-0-0-bug-fixes "Permalink to this headline") * Fix issue #288 : \_\_name\_\_ and other attributes for async functions * Use str.format to format the logs internally to make logging compatible with other logger such as loguru. ### Other Notes[¶](https://tenacity.readthedocs.io/en/latest/changelog.html#relnotes-8-0-0-other-notes "Permalink to this headline") * Use black for code formatting and validate using black –check. Code compatibility: py26-py39. * Enforce maximal line length to 120 symbols * Add type annotations to cover all public API. * Do not package tests with tenacity. * Drop support for deprecated Python versions (2.7 and 3.5) * Corrected the PyPI-published wheel tag to match the metadata saying that the release is Python 3 only. 6.3.0[¶](https://tenacity.readthedocs.io/en/latest/changelog.html#relnotes-6-3-0 "Permalink to this headline") --------------------------------------------------------------------------------------------------------------- ### Other Notes[¶](https://tenacity.readthedocs.io/en/latest/changelog.html#relnotes-6-3-0-other-notes "Permalink to this headline") * Unit tests can now mock `nap.sleep()` for testing in all tenacity usage styles 6.2.0[¶](https://tenacity.readthedocs.io/en/latest/changelog.html#relnotes-6-2-0 "Permalink to this headline") --------------------------------------------------------------------------------------------------------------- ### New Features[¶](https://tenacity.readthedocs.io/en/latest/changelog.html#relnotes-6-2-0-new-features "Permalink to this headline") * Add an `exc_info` option to the `before_sleep_log()` strategy. 5.1.0[¶](https://tenacity.readthedocs.io/en/latest/changelog.html#relnotes-5-1-0 "Permalink to this headline") --------------------------------------------------------------------------------------------------------------- ### New Features[¶](https://tenacity.readthedocs.io/en/latest/changelog.html#relnotes-5-1-0-new-features "Permalink to this headline") * Add reno (changelog system) --- # API Reference — Tenacity documentation * [Docs](https://tenacity.readthedocs.io/en/latest/index.html) » * API Reference * [Edit on GitHub](https://github.com/jd/tenacity/blob/master/doc/source/api.rst) * * * API Reference[¶](https://tenacity.readthedocs.io/en/latest/api.html#api-reference "Permalink to this headline") ================================================================================================================ Retry Main API[¶](https://tenacity.readthedocs.io/en/latest/api.html#retry-main-api "Permalink to this headline") ------------------------------------------------------------------------------------------------------------------ `tenacity.``retry`(_\*dargs_, _\*\*dkw_) → Any Wrap a function with a new Retrying object. | | | | --- | --- | | Parameters: | * **dargs** – positional arguments passed to Retrying object
* **dkw** – keyword arguments passed to the Retrying object | _class_ `tenacity.``Retrying`(_sleep: Callable\[\[Union\[int, float\]\], None\] = , stop: StopBaseT = , wait: WaitBaseT = , retry: RetryBaseT = , before: Callable\[\[RetryCallState\], None\] = , after: Callable\[\[RetryCallState\], None\] = , before\_sleep: Optional\[Callable\[\[RetryCallState\], None\]\] = None, reraise: bool = False, retry\_error\_cls: Type\[tenacity.RetryError\] = , retry\_error\_callback: Optional\[Callable\[\[RetryCallState\], Any\]\] = None_)[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.Retrying "Permalink to this definition") Retrying controller. _class_ `tenacity.``AsyncRetrying`(_sleep: Callable\[\[float\], Awaitable\[Any\]\] = , \*\*kwargs_)[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.AsyncRetrying "Permalink to this definition") `wraps`(_fn: WrappedFn_) → WrappedFn[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.AsyncRetrying.wraps "Permalink to this definition") Wrap a function for retrying. | | | | --- | --- | | Parameters: | **f** – A function to wraps for retrying. | _class_ `tenacity.tornadoweb.``TornadoRetrying`(_sleep: typing.Callable\[\[float\], Future\[None\]\] = , \*\*kwargs_)[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.tornadoweb.TornadoRetrying "Permalink to this definition") After Functions[¶](https://tenacity.readthedocs.io/en/latest/api.html#after-functions "Permalink to this headline") -------------------------------------------------------------------------------------------------------------------- Those functions can be used as the after keyword argument of [`tenacity.retry()`](https://tenacity.readthedocs.io/en/latest/api.html#module-tenacity.retry "tenacity.retry") . `tenacity.after.``after_log`(_logger: logging.Logger_, _log\_level: int_, _sec\_format: str = '%0.3f'_) → Callable\[\[RetryCallState\], None\][¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.after.after_log "Permalink to this definition") After call strategy that logs to some logger the finished attempt. `tenacity.after.``after_nothing`(_retry\_state: RetryCallState_) → None[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.after.after_nothing "Permalink to this definition") After call strategy that does nothing. Before Functions[¶](https://tenacity.readthedocs.io/en/latest/api.html#before-functions "Permalink to this headline") ---------------------------------------------------------------------------------------------------------------------- Those functions can be used as the before keyword argument of [`tenacity.retry()`](https://tenacity.readthedocs.io/en/latest/api.html#module-tenacity.retry "tenacity.retry") . `tenacity.before.``before_log`(_logger: logging.Logger_, _log\_level: int_) → Callable\[\[RetryCallState\], None\][¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.before.before_log "Permalink to this definition") Before call strategy that logs to some logger the attempt. `tenacity.before.``before_nothing`(_retry\_state: RetryCallState_) → None[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.before.before_nothing "Permalink to this definition") Before call strategy that does nothing. Before Sleep Functions[¶](https://tenacity.readthedocs.io/en/latest/api.html#before-sleep-functions "Permalink to this headline") ---------------------------------------------------------------------------------------------------------------------------------- Those functions can be used as the before\_sleep keyword argument of [`tenacity.retry()`](https://tenacity.readthedocs.io/en/latest/api.html#module-tenacity.retry "tenacity.retry") . `tenacity.before_sleep.``before_sleep_log`(_logger: logging.Logger_, _log\_level: int_, _exc\_info: bool = False_) → Callable\[\[RetryCallState\], None\][¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.before_sleep.before_sleep_log "Permalink to this definition") Before call strategy that logs to some logger the attempt. `tenacity.before_sleep.``before_sleep_nothing`(_retry\_state: RetryCallState_) → None[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.before_sleep.before_sleep_nothing "Permalink to this definition") Before call strategy that does nothing. Nap Functions[¶](https://tenacity.readthedocs.io/en/latest/api.html#nap-functions "Permalink to this headline") ---------------------------------------------------------------------------------------------------------------- Those functions can be used as the sleep keyword argument of [`tenacity.retry()`](https://tenacity.readthedocs.io/en/latest/api.html#module-tenacity.retry "tenacity.retry") . `tenacity.nap.``sleep`(_seconds: float_) → None[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.nap.sleep "Permalink to this definition") Sleep strategy that delays execution for a given number of seconds. This is the default strategy, and may be mocked out for unit testing. _class_ `tenacity.nap.``sleep_using_event`(_event: threading.Event_)[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.nap.sleep_using_event "Permalink to this definition") Sleep strategy that waits on an event to be set. Retry Functions[¶](https://tenacity.readthedocs.io/en/latest/api.html#retry-functions "Permalink to this headline") -------------------------------------------------------------------------------------------------------------------- Those functions can be used as the retry keyword argument of [`tenacity.retry()`](https://tenacity.readthedocs.io/en/latest/api.html#module-tenacity.retry "tenacity.retry") . _class_ `tenacity.retry.``retry_all`(_\*retries_)[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.retry.retry_all "Permalink to this definition") Retries if all the retries condition are valid. _class_ `tenacity.retry.``retry_any`(_\*retries_)[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.retry.retry_any "Permalink to this definition") Retries if any of the retries condition is valid. _class_ `tenacity.retry.``retry_base`[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.retry.retry_base "Permalink to this definition") Abstract base class for retry strategies. _class_ `tenacity.retry.``retry_if_exception`(_predicate: Callable\[\[BaseException\], bool\]_)[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.retry.retry_if_exception "Permalink to this definition") Retry strategy that retries if an exception verifies a predicate. _class_ `tenacity.retry.``retry_if_exception_cause_type`(_exception\_types: Union\[Type\[BaseException\], Tuple\[Type\[BaseException\], ...\]\] = _)[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.retry.retry_if_exception_cause_type "Permalink to this definition") Retries if any of the causes of the raised exception is of one or more types. The check on the type of the cause of the exception is done recursively (until finding an exception in the chain that has no \_\_cause\_\_) _class_ `tenacity.retry.``retry_if_exception_message`(_message: Optional\[str\] = None_, _match: Optional\[str\] = None_)[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.retry.retry_if_exception_message "Permalink to this definition") Retries if an exception message equals or matches. _class_ `tenacity.retry.``retry_if_exception_type`(_exception\_types: Union\[Type\[BaseException\], Tuple\[Type\[BaseException\], ...\]\] = _)[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.retry.retry_if_exception_type "Permalink to this definition") Retries if an exception has been raised of one or more types. _class_ `tenacity.retry.``retry_if_not_exception_message`(_message: Optional\[str\] = None_, _match: Optional\[str\] = None_)[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.retry.retry_if_not_exception_message "Permalink to this definition") Retries until an exception message equals or matches. _class_ `tenacity.retry.``retry_if_not_exception_type`(_exception\_types: Union\[Type\[BaseException\], Tuple\[Type\[BaseException\], ...\]\] = _)[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.retry.retry_if_not_exception_type "Permalink to this definition") Retries except an exception has been raised of one or more types. _class_ `tenacity.retry.``retry_if_not_result`(_predicate: Callable\[\[Any\], bool\]_)[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.retry.retry_if_not_result "Permalink to this definition") Retries if the result refutes a predicate. _class_ `tenacity.retry.``retry_if_result`(_predicate: Callable\[\[Any\], bool\]_)[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.retry.retry_if_result "Permalink to this definition") Retries if the result verifies a predicate. _class_ `tenacity.retry.``retry_unless_exception_type`(_exception\_types: Union\[Type\[BaseException\], Tuple\[Type\[BaseException\], ...\]\] = _)[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.retry.retry_unless_exception_type "Permalink to this definition") Retries until an exception is raised of one or more types. Stop Functions[¶](https://tenacity.readthedocs.io/en/latest/api.html#stop-functions "Permalink to this headline") ------------------------------------------------------------------------------------------------------------------ Those functions can be used as the stop keyword argument of [`tenacity.retry()`](https://tenacity.readthedocs.io/en/latest/api.html#module-tenacity.retry "tenacity.retry") . _class_ `tenacity.stop.``stop_after_attempt`(_max\_attempt\_number: int_)[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.stop.stop_after_attempt "Permalink to this definition") Stop when the previous attempt >= max\_attempt. _class_ `tenacity.stop.``stop_after_delay`(_max\_delay: Union\[int, float, datetime.timedelta\]_)[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.stop.stop_after_delay "Permalink to this definition") Stop when the time from the first attempt >= limit. _class_ `tenacity.stop.``stop_all`(_\*stops_)[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.stop.stop_all "Permalink to this definition") Stop if all the stop conditions are valid. _class_ `tenacity.stop.``stop_any`(_\*stops_)[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.stop.stop_any "Permalink to this definition") Stop if any of the stop condition is valid. _class_ `tenacity.stop.``stop_base`[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.stop.stop_base "Permalink to this definition") Abstract base class for stop strategies. _class_ `tenacity.stop.``stop_when_event_set`(_event: threading.Event_)[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.stop.stop_when_event_set "Permalink to this definition") Stop when the given event is set. Wait Functions[¶](https://tenacity.readthedocs.io/en/latest/api.html#wait-functions "Permalink to this headline") ------------------------------------------------------------------------------------------------------------------ Those functions can be used as the wait keyword argument of [`tenacity.retry()`](https://tenacity.readthedocs.io/en/latest/api.html#module-tenacity.retry "tenacity.retry") . _class_ `tenacity.wait.``wait_base`[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.wait.wait_base "Permalink to this definition") Abstract base class for wait strategies. _class_ `tenacity.wait.``wait_chain`(_\*strategies_)[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.wait.wait_chain "Permalink to this definition") Chain two or more waiting strategies. If all strategies are exhausted, the very last strategy is used thereafter. For example: @retry(wait\=wait\_chain(\*\[wait\_fixed(1) for i in range(3)\] + \[wait\_fixed(2) for j in range(5)\] + \[wait\_fixed(5) for k in range(4)))\ def wait\_chained():\ print("Wait 1s for 3 attempts, 2s for 5 attempts and 5s\ thereafter.")\ \ _class_ `tenacity.wait.``wait_combine`(_\*strategies_)[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.wait.wait_combine "Permalink to this definition")\ \ Combine several waiting strategies.\ \ _class_ `tenacity.wait.``wait_exponential`(_multiplier: Union\[int_, _float\] = 1_, _max: Union\[int_, _float_, _datetime.timedelta\] = 4.611686018427388e+18_, _exp\_base: Union\[int_, _float\] = 2_, _min: Union\[int_, _float_, _datetime.timedelta\] = 0_)[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.wait.wait_exponential "Permalink to this definition")\ \ Wait strategy that applies exponential backoff.\ \ It allows for a customized multiplier and an ability to restrict the upper and lower limits to some maximum and minimum value.\ \ The intervals are fixed (i.e. there is no jitter), so this strategy is suitable for balancing retries against latency when a required resource is unavailable for an unknown duration, but _not_ suitable for resolving contention between multiple processes for a shared resource. Use wait\_random\_exponential for the latter case.\ \ _class_ `tenacity.wait.``wait_exponential_jitter`(_initial: float = 1_, _max: float = 4.611686018427388e+18_, _exp\_base: float = 2_, _jitter: float = 1_)[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.wait.wait_exponential_jitter "Permalink to this definition")\ \ Wait strategy that applies exponential backoff and jitter.\ \ It allows for a customized initial wait, maximum wait and jitter.\ \ This implements the strategy described here: [https://cloud.google.com/storage/docs/retry-strategy](https://cloud.google.com/storage/docs/retry-strategy)\ \ The wait time is min(initial \* 2\*\*n + random.uniform(0, jitter), maximum) where n is the retry count.\ \ _class_ `tenacity.wait.``wait_fixed`(_wait: Union\[int, float, datetime.timedelta\]_)[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.wait.wait_fixed "Permalink to this definition")\ \ Wait strategy that waits a fixed amount of time between each retry.\ \ _class_ `tenacity.wait.``wait_incrementing`(_start: Union\[int_, _float_, _datetime.timedelta\] = 0_, _increment: Union\[int_, _float_, _datetime.timedelta\] = 100_, _max: Union\[int_, _float_, _datetime.timedelta\] = 4.611686018427388e+18_)[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.wait.wait_incrementing "Permalink to this definition")\ \ Wait an incremental amount of time after each attempt.\ \ Starting at a starting value and incrementing by a value for each attempt (and restricting the upper limit to some maximum value).\ \ _class_ `tenacity.wait.``wait_none`[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.wait.wait_none "Permalink to this definition")\ \ Wait strategy that doesn’t wait at all before retrying.\ \ _class_ `tenacity.wait.``wait_random`(_min: Union\[int_, _float_, _datetime.timedelta\] = 0_, _max: Union\[int_, _float_, _datetime.timedelta\] = 1_)[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.wait.wait_random "Permalink to this definition")\ \ Wait strategy that waits a random amount of time between min/max.\ \ _class_ `tenacity.wait.``wait_random_exponential`(_multiplier: Union\[int_, _float\] = 1_, _max: Union\[int_, _float_, _datetime.timedelta\] = 4.611686018427388e+18_, _exp\_base: Union\[int_, _float\] = 2_, _min: Union\[int_, _float_, _datetime.timedelta\] = 0_)[¶](https://tenacity.readthedocs.io/en/latest/api.html#tenacity.wait.wait_random_exponential "Permalink to this definition")\ \ Random wait with exponentially widening window.\ \ An exponential backoff strategy used to mediate contention between multiple uncoordinated processes for a shared resource in distributed systems. This is the sense in which “exponential backoff” is meant in e.g. Ethernet networking, and corresponds to the “Full Jitter” algorithm described in this blog post:\ \ [https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/](https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/)\ \ Each retry occurs at a random time in a geometrically expanding interval. It allows for a custom multiplier and an ability to restrict the upper limit of the random interval to some maximum value.\ \ Example:\ \ wait\_random\_exponential(multiplier\=0.5, \# initial window 0.5s\ max\=60) \# max 60s timeout\ \ When waiting for an unavailable resource to become available again, as opposed to trying to resolve contention for a shared resource, the wait\_exponential strategy (which uses a fixed interval) may be preferable. --- # Changelog — Tenacity documentation * [Docs](https://tenacity.readthedocs.io/en/stable/index.html) » * Changelog * [Edit on GitHub](https://github.com/jd/tenacity/blob/548c5d490187af6f339cbffdd0add38aecc3ecb0/doc/source/changelog.rst) * * * Changelog[¶](https://tenacity.readthedocs.io/en/stable/changelog.html#changelog "Permalink to this heading") ============================================================================================================= 8.2.2[¶](https://tenacity.readthedocs.io/en/stable/changelog.html#relnotes-8-2-2 "Permalink to this heading") -------------------------------------------------------------------------------------------------------------- ### Bug Fixes[¶](https://tenacity.readthedocs.io/en/stable/changelog.html#bug-fixes "Permalink to this heading") * Argument wait was improperly annotated, making mypy checks fail. Now it’s annotated as typing.Union\[wait\_base, typing.Callable\[\[“RetryCallState”\], typing.Union\[float, int\]\]\] ### Other Notes[¶](https://tenacity.readthedocs.io/en/stable/changelog.html#other-notes "Permalink to this heading") * Add retry\_if\_exception\_cause\_type\`and \`wait\_exponential\_jitter to \_\_all\_\_ of init.py 8.2.0[¶](https://tenacity.readthedocs.io/en/stable/changelog.html#relnotes-8-2-0 "Permalink to this heading") -------------------------------------------------------------------------------------------------------------- ### Prelude[¶](https://tenacity.readthedocs.io/en/stable/changelog.html#prelude "Permalink to this heading") Clarify usage of reraise keyword argument ### New Features[¶](https://tenacity.readthedocs.io/en/stable/changelog.html#new-features "Permalink to this heading") * Explicitly export convenience symbols from tenacity root module * * accept `datetime.timedelta` instances as argument to `tenacity.stop.stop_after_delay` ### Bug Fixes[¶](https://tenacity.readthedocs.io/en/stable/changelog.html#relnotes-8-2-0-bug-fixes "Permalink to this heading") * Fix async loop with retrying code block when result is available. * AsyncRetrying was erroneously implementing \_\_iter\_\_(), making tenacity retrying mechanism working but in a synchronous fashion and not waiting as expected. This interface has been removed, \_\_aiter\_\_() should be used instead. 8.1.0[¶](https://tenacity.readthedocs.io/en/stable/changelog.html#relnotes-8-1-0 "Permalink to this heading") -------------------------------------------------------------------------------------------------------------- ### New Features[¶](https://tenacity.readthedocs.io/en/stable/changelog.html#relnotes-8-1-0-new-features "Permalink to this heading") * Add a new retry\_base class called retry\_if\_exception\_cause\_type that checks, recursively, if any of the causes of the raised exception is of a certain type. * Add `datetime.timedelta` as accepted wait unit type. * Implement a wait.wait\_exponential\_jitter per Google’s storage retry guide. See [https://cloud.google.com/storage/docs/retry-strategy](https://cloud.google.com/storage/docs/retry-strategy) ### Bug Fixes[¶](https://tenacity.readthedocs.io/en/stable/changelog.html#relnotes-8-1-0-bug-fixes "Permalink to this heading") * Sphinx build error where Sphinx complains about an undefined class. 8.0.1[¶](https://tenacity.readthedocs.io/en/stable/changelog.html#relnotes-8-0-1 "Permalink to this heading") -------------------------------------------------------------------------------------------------------------- ### Bug Fixes[¶](https://tenacity.readthedocs.io/en/stable/changelog.html#relnotes-8-0-1-bug-fixes "Permalink to this heading") * Fix after\_log logger format: function name was used with delay formatting. 8.0.0[¶](https://tenacity.readthedocs.io/en/stable/changelog.html#relnotes-8-0-0 "Permalink to this heading") -------------------------------------------------------------------------------------------------------------- ### New Features[¶](https://tenacity.readthedocs.io/en/stable/changelog.html#relnotes-8-0-0-new-features "Permalink to this heading") * Add `retry_if_not_exception_type()` that allows to retry if a raised exception doesn’t match given exceptions. * Most part of the code is type annotated. * Python 3.10 support has been added. * Add a `__repr__` method to `RetryCallState` objects for easier debugging. ### Upgrade Notes[¶](https://tenacity.readthedocs.io/en/stable/changelog.html#upgrade-notes "Permalink to this heading") * Removed BaseRetrying.call: was long time deprecated and produced DeprecationWarning * Removed BaseRetrying.fn: was noted as deprecated * API change: BaseRetrying.begin() do not require arguments anymore as it not setting BaseRetrying.fn ### Bug Fixes[¶](https://tenacity.readthedocs.io/en/stable/changelog.html#relnotes-8-0-0-bug-fixes "Permalink to this heading") * Fix issue #288 : \_\_name\_\_ and other attributes for async functions * Use str.format to format the logs internally to make logging compatible with other logger such as loguru. ### Other Notes[¶](https://tenacity.readthedocs.io/en/stable/changelog.html#relnotes-8-0-0-other-notes "Permalink to this heading") * Use black for code formatting and validate using black –check. Code compatibility: py26-py39. * Enforce maximal line length to 120 symbols * Add type annotations to cover all public API. * Do not package tests with tenacity. * Drop support for deprecated Python versions (2.7 and 3.5) * Corrected the PyPI-published wheel tag to match the metadata saying that the release is Python 3 only. 6.3.0[¶](https://tenacity.readthedocs.io/en/stable/changelog.html#relnotes-6-3-0 "Permalink to this heading") -------------------------------------------------------------------------------------------------------------- ### Other Notes[¶](https://tenacity.readthedocs.io/en/stable/changelog.html#relnotes-6-3-0-other-notes "Permalink to this heading") * Unit tests can now mock `nap.sleep()` for testing in all tenacity usage styles 6.2.0[¶](https://tenacity.readthedocs.io/en/stable/changelog.html#relnotes-6-2-0 "Permalink to this heading") -------------------------------------------------------------------------------------------------------------- ### New Features[¶](https://tenacity.readthedocs.io/en/stable/changelog.html#relnotes-6-2-0-new-features "Permalink to this heading") * Add an `exc_info` option to the `before_sleep_log()` strategy. 5.1.0[¶](https://tenacity.readthedocs.io/en/stable/changelog.html#relnotes-5-1-0 "Permalink to this heading") -------------------------------------------------------------------------------------------------------------- ### New Features[¶](https://tenacity.readthedocs.io/en/stable/changelog.html#relnotes-5-1-0-new-features "Permalink to this heading") * Add reno (changelog system) --- # API Reference — Tenacity documentation * [Docs](https://tenacity.readthedocs.io/en/stable/index.html) » * API Reference * [Edit on GitHub](https://github.com/jd/tenacity/blob/548c5d490187af6f339cbffdd0add38aecc3ecb0/doc/source/api.rst) * * * API Reference[¶](https://tenacity.readthedocs.io/en/stable/api.html#api-reference "Permalink to this heading") =============================================================================================================== Retry Main API[¶](https://tenacity.readthedocs.io/en/stable/api.html#retry-main-api "Permalink to this heading") ----------------------------------------------------------------------------------------------------------------- tenacity.retry(_func: WrappedFn_) → WrappedFn tenacity.retry(_sleep: Callable\[\[Union\[int, float\]\], None\] \= sleep_, _stop: StopBaseT \= stop\_never_, _wait: WaitBaseT \= wait\_none()_, _retry: RetryBaseT \= retry\_if\_exception\_type()_, _before: Callable\[\[[RetryCallState](https://tenacity.readthedocs.io/en/stable/index.html#tenacity.RetryCallState "tenacity.RetryCallState")\ \], None\] \= before\_nothing_, _after: Callable\[\[[RetryCallState](https://tenacity.readthedocs.io/en/stable/index.html#tenacity.RetryCallState "tenacity.RetryCallState")\ \], None\] \= after\_nothing_, _before\_sleep: Optional\[Callable\[\[[RetryCallState](https://tenacity.readthedocs.io/en/stable/index.html#tenacity.RetryCallState "tenacity.RetryCallState")\ \], None\]\] \= None_, _reraise: bool \= False_, _retry\_error\_cls: Type\[RetryError\] \= RetryError_, _retry\_error\_callback: Optional\[Callable\[\[[RetryCallState](https://tenacity.readthedocs.io/en/stable/index.html#tenacity.RetryCallState "tenacity.RetryCallState")\ \], Any\]\] \= None_) → Callable\[\[WrappedFn\], WrappedFn\] Wrap a function with a new Retrying object. Parameters: * **dargs** – positional arguments passed to Retrying object * **dkw** – keyword arguments passed to the Retrying object _class_ tenacity.Retrying(_sleep: ~typing.Callable\[\[~typing.Union\[int, float\]\], None\] \= , stop: StopBaseT \= , wait: WaitBaseT \= , retry: RetryBaseT \= , before: ~typing.Callable\[\[RetryCallState\], None\] \= , after: ~typing.Callable\[\[RetryCallState\], None\] \= , before\_sleep: ~typing.Optional\[~typing.Callable\[\[RetryCallState\], None\]\] \= None, reraise: bool \= False, retry\_error\_cls: ~typing.Type\[~tenacity.RetryError\] \= , retry\_error\_callback: ~typing.Optional\[~typing.Callable\[\[RetryCallState\], ~typing.Any\]\] \= None_)[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.Retrying "Permalink to this definition") Retrying controller. _class_ tenacity.AsyncRetrying(_sleep: ~typing.Callable\[\[float\], ~typing.Awaitable\[~typing.Any\]\] \= , \*\*kwargs: ~typing.Any_)[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.AsyncRetrying "Permalink to this definition") wraps(_fn: WrappedFn_) → WrappedFn[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.AsyncRetrying.wraps "Permalink to this definition") Wrap a function for retrying. Parameters: **f** – A function to wraps for retrying. _class_ tenacity.tornadoweb.TornadoRetrying(_sleep: typing.Callable\[\[float\], Future\[None\]\] \= , \*\*kwargs: ~typing.Any_)[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.tornadoweb.TornadoRetrying "Permalink to this definition") After Functions[¶](https://tenacity.readthedocs.io/en/stable/api.html#after-functions "Permalink to this heading") ------------------------------------------------------------------------------------------------------------------- Those functions can be used as the after keyword argument of [`tenacity.retry()`](https://tenacity.readthedocs.io/en/stable/api.html#module-tenacity.retry "tenacity.retry") . tenacity.after.after\_log(_logger: logging.Logger_, _log\_level: int_, _sec\_format: str \= '%0.3f'_) → Callable\[\[[RetryCallState](https://tenacity.readthedocs.io/en/stable/index.html#tenacity.RetryCallState "tenacity.RetryCallState")\ \], None\][¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.after.after_log "Permalink to this definition") After call strategy that logs to some logger the finished attempt. tenacity.after.after\_nothing(_retry\_state: [RetryCallState](https://tenacity.readthedocs.io/en/stable/index.html#tenacity.RetryCallState "tenacity.RetryCallState") _) → None[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.after.after_nothing "Permalink to this definition") After call strategy that does nothing. Before Functions[¶](https://tenacity.readthedocs.io/en/stable/api.html#before-functions "Permalink to this heading") --------------------------------------------------------------------------------------------------------------------- Those functions can be used as the before keyword argument of [`tenacity.retry()`](https://tenacity.readthedocs.io/en/stable/api.html#module-tenacity.retry "tenacity.retry") . tenacity.before.before\_log(_logger: logging.Logger_, _log\_level: int_) → Callable\[\[[RetryCallState](https://tenacity.readthedocs.io/en/stable/index.html#tenacity.RetryCallState "tenacity.RetryCallState")\ \], None\][¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.before.before_log "Permalink to this definition") Before call strategy that logs to some logger the attempt. tenacity.before.before\_nothing(_retry\_state: [RetryCallState](https://tenacity.readthedocs.io/en/stable/index.html#tenacity.RetryCallState "tenacity.RetryCallState") _) → None[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.before.before_nothing "Permalink to this definition") Before call strategy that does nothing. Before Sleep Functions[¶](https://tenacity.readthedocs.io/en/stable/api.html#before-sleep-functions "Permalink to this heading") --------------------------------------------------------------------------------------------------------------------------------- Those functions can be used as the before\_sleep keyword argument of [`tenacity.retry()`](https://tenacity.readthedocs.io/en/stable/api.html#module-tenacity.retry "tenacity.retry") . tenacity.before\_sleep.before\_sleep\_log(_logger: logging.Logger_, _log\_level: int_, _exc\_info: bool \= False_) → Callable\[\[[RetryCallState](https://tenacity.readthedocs.io/en/stable/index.html#tenacity.RetryCallState "tenacity.RetryCallState")\ \], None\][¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.before_sleep.before_sleep_log "Permalink to this definition") Before call strategy that logs to some logger the attempt. tenacity.before\_sleep.before\_sleep\_nothing(_retry\_state: [RetryCallState](https://tenacity.readthedocs.io/en/stable/index.html#tenacity.RetryCallState "tenacity.RetryCallState") _) → None[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.before_sleep.before_sleep_nothing "Permalink to this definition") Before call strategy that does nothing. Nap Functions[¶](https://tenacity.readthedocs.io/en/stable/api.html#nap-functions "Permalink to this heading") --------------------------------------------------------------------------------------------------------------- Those functions can be used as the sleep keyword argument of [`tenacity.retry()`](https://tenacity.readthedocs.io/en/stable/api.html#module-tenacity.retry "tenacity.retry") . tenacity.nap.sleep(_seconds: float_) → None[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.nap.sleep "Permalink to this definition") Sleep strategy that delays execution for a given number of seconds. This is the default strategy, and may be mocked out for unit testing. _class_ tenacity.nap.sleep\_using\_event(_event: threading.Event_)[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.nap.sleep_using_event "Permalink to this definition") Sleep strategy that waits on an event to be set. Retry Functions[¶](https://tenacity.readthedocs.io/en/stable/api.html#retry-functions "Permalink to this heading") ------------------------------------------------------------------------------------------------------------------- Those functions can be used as the retry keyword argument of [`tenacity.retry()`](https://tenacity.readthedocs.io/en/stable/api.html#module-tenacity.retry "tenacity.retry") . _class_ tenacity.retry.retry\_all(_\*retries: [retry\_base](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.retry.retry_base "tenacity.retry.retry_base") _)[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.retry.retry_all "Permalink to this definition") Retries if all the retries condition are valid. _class_ tenacity.retry.retry\_any(_\*retries: [retry\_base](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.retry.retry_base "tenacity.retry.retry_base") _)[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.retry.retry_any "Permalink to this definition") Retries if any of the retries condition is valid. _class_ tenacity.retry.retry\_base[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.retry.retry_base "Permalink to this definition") Abstract base class for retry strategies. _class_ tenacity.retry.retry\_if\_exception(_predicate: Callable\[\[BaseException\], bool\]_)[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.retry.retry_if_exception "Permalink to this definition") Retry strategy that retries if an exception verifies a predicate. _class_ tenacity.retry.retry\_if\_exception\_cause\_type(_exception\_types: ~typing.Union\[~typing.Type\[BaseException\], ~typing.Tuple\[~typing.Type\[BaseException\], ...\]\] \= _)[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.retry.retry_if_exception_cause_type "Permalink to this definition") Retries if any of the causes of the raised exception is of one or more types. The check on the type of the cause of the exception is done recursively (until finding an exception in the chain that has no \_\_cause\_\_) _class_ tenacity.retry.retry\_if\_exception\_message(_message: Optional\[str\] \= None_, _match: Optional\[str\] \= None_)[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.retry.retry_if_exception_message "Permalink to this definition") Retries if an exception message equals or matches. _class_ tenacity.retry.retry\_if\_exception\_type(_exception\_types: ~typing.Union\[~typing.Type\[BaseException\], ~typing.Tuple\[~typing.Type\[BaseException\], ...\]\] \= _)[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.retry.retry_if_exception_type "Permalink to this definition") Retries if an exception has been raised of one or more types. _class_ tenacity.retry.retry\_if\_not\_exception\_message(_message: Optional\[str\] \= None_, _match: Optional\[str\] \= None_)[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.retry.retry_if_not_exception_message "Permalink to this definition") Retries until an exception message equals or matches. _class_ tenacity.retry.retry\_if\_not\_exception\_type(_exception\_types: ~typing.Union\[~typing.Type\[BaseException\], ~typing.Tuple\[~typing.Type\[BaseException\], ...\]\] \= _)[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.retry.retry_if_not_exception_type "Permalink to this definition") Retries except an exception has been raised of one or more types. _class_ tenacity.retry.retry\_if\_not\_result(_predicate: Callable\[\[Any\], bool\]_)[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.retry.retry_if_not_result "Permalink to this definition") Retries if the result refutes a predicate. _class_ tenacity.retry.retry\_if\_result(_predicate: Callable\[\[Any\], bool\]_)[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.retry.retry_if_result "Permalink to this definition") Retries if the result verifies a predicate. _class_ tenacity.retry.retry\_unless\_exception\_type(_exception\_types: ~typing.Union\[~typing.Type\[BaseException\], ~typing.Tuple\[~typing.Type\[BaseException\], ...\]\] \= _)[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.retry.retry_unless_exception_type "Permalink to this definition") Retries until an exception is raised of one or more types. Stop Functions[¶](https://tenacity.readthedocs.io/en/stable/api.html#stop-functions "Permalink to this heading") ----------------------------------------------------------------------------------------------------------------- Those functions can be used as the stop keyword argument of [`tenacity.retry()`](https://tenacity.readthedocs.io/en/stable/api.html#module-tenacity.retry "tenacity.retry") . _class_ tenacity.stop.stop\_after\_attempt(_max\_attempt\_number: int_)[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.stop.stop_after_attempt "Permalink to this definition") Stop when the previous attempt >= max\_attempt. _class_ tenacity.stop.stop\_after\_delay(_max\_delay: Union\[int, float, timedelta\]_)[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.stop.stop_after_delay "Permalink to this definition") Stop when the time from the first attempt >= limit. _class_ tenacity.stop.stop\_all(_\*stops: [stop\_base](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.stop.stop_base "tenacity.stop.stop_base") _)[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.stop.stop_all "Permalink to this definition") Stop if all the stop conditions are valid. _class_ tenacity.stop.stop\_any(_\*stops: [stop\_base](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.stop.stop_base "tenacity.stop.stop_base") _)[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.stop.stop_any "Permalink to this definition") Stop if any of the stop condition is valid. _class_ tenacity.stop.stop\_base[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.stop.stop_base "Permalink to this definition") Abstract base class for stop strategies. _class_ tenacity.stop.stop\_when\_event\_set(_event: threading.Event_)[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.stop.stop_when_event_set "Permalink to this definition") Stop when the given event is set. Wait Functions[¶](https://tenacity.readthedocs.io/en/stable/api.html#wait-functions "Permalink to this heading") ----------------------------------------------------------------------------------------------------------------- Those functions can be used as the wait keyword argument of [`tenacity.retry()`](https://tenacity.readthedocs.io/en/stable/api.html#module-tenacity.retry "tenacity.retry") . _class_ tenacity.wait.wait\_base[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.wait.wait_base "Permalink to this definition") Abstract base class for wait strategies. _class_ tenacity.wait.wait\_chain(_\*strategies: [wait\_base](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.wait.wait_base "tenacity.wait.wait_base") _)[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.wait.wait_chain "Permalink to this definition") Chain two or more waiting strategies. If all strategies are exhausted, the very last strategy is used thereafter. For example: @retry(wait\=wait\_chain(\*\[wait\_fixed(1) for i in range(3)\] + \[wait\_fixed(2) for j in range(5)\] + \[wait\_fixed(5) for k in range(4)))\ def wait\_chained():\ print("Wait 1s for 3 attempts, 2s for 5 attempts and 5s\ thereafter.")\ \ _class_ tenacity.wait.wait\_combine(_\*strategies: [wait\_base](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.wait.wait_base "tenacity.wait.wait_base")\ _)[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.wait.wait_combine "Permalink to this definition")\ \ Combine several waiting strategies.\ \ _class_ tenacity.wait.wait\_exponential(_multiplier: Union\[int, float\] \= 1_, _max: Union\[int, float, timedelta\] \= 4.611686018427388e+18_, _exp\_base: Union\[int, float\] \= 2_, _min: Union\[int, float, timedelta\] \= 0_)[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.wait.wait_exponential "Permalink to this definition")\ \ Wait strategy that applies exponential backoff.\ \ It allows for a customized multiplier and an ability to restrict the upper and lower limits to some maximum and minimum value.\ \ The intervals are fixed (i.e. there is no jitter), so this strategy is suitable for balancing retries against latency when a required resource is unavailable for an unknown duration, but _not_ suitable for resolving contention between multiple processes for a shared resource. Use wait\_random\_exponential for the latter case.\ \ _class_ tenacity.wait.wait\_exponential\_jitter(_initial: float \= 1_, _max: float \= 4.611686018427388e+18_, _exp\_base: float \= 2_, _jitter: float \= 1_)[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.wait.wait_exponential_jitter "Permalink to this definition")\ \ Wait strategy that applies exponential backoff and jitter.\ \ It allows for a customized initial wait, maximum wait and jitter.\ \ This implements the strategy described here: [https://cloud.google.com/storage/docs/retry-strategy](https://cloud.google.com/storage/docs/retry-strategy)\ \ The wait time is min(initial \* 2\*\*n + random.uniform(0, jitter), maximum) where n is the retry count.\ \ _class_ tenacity.wait.wait\_fixed(_wait: Union\[int, float, timedelta\]_)[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.wait.wait_fixed "Permalink to this definition")\ \ Wait strategy that waits a fixed amount of time between each retry.\ \ _class_ tenacity.wait.wait\_incrementing(_start: Union\[int, float, timedelta\] \= 0_, _increment: Union\[int, float, timedelta\] \= 100_, _max: Union\[int, float, timedelta\] \= 4.611686018427388e+18_)[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.wait.wait_incrementing "Permalink to this definition")\ \ Wait an incremental amount of time after each attempt.\ \ Starting at a starting value and incrementing by a value for each attempt (and restricting the upper limit to some maximum value).\ \ _class_ tenacity.wait.wait\_none[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.wait.wait_none "Permalink to this definition")\ \ Wait strategy that doesn’t wait at all before retrying.\ \ _class_ tenacity.wait.wait\_random(_min: Union\[int, float, timedelta\] \= 0_, _max: Union\[int, float, timedelta\] \= 1_)[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.wait.wait_random "Permalink to this definition")\ \ Wait strategy that waits a random amount of time between min/max.\ \ _class_ tenacity.wait.wait\_random\_exponential(_multiplier: Union\[int, float\] \= 1_, _max: Union\[int, float, timedelta\] \= 4.611686018427388e+18_, _exp\_base: Union\[int, float\] \= 2_, _min: Union\[int, float, timedelta\] \= 0_)[¶](https://tenacity.readthedocs.io/en/stable/api.html#tenacity.wait.wait_random_exponential "Permalink to this definition")\ \ Random wait with exponentially widening window.\ \ An exponential backoff strategy used to mediate contention between multiple uncoordinated processes for a shared resource in distributed systems. This is the sense in which “exponential backoff” is meant in e.g. Ethernet networking, and corresponds to the “Full Jitter” algorithm described in this blog post:\ \ [https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/](https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/)\ \ Each retry occurs at a random time in a geometrically expanding interval. It allows for a custom multiplier and an ability to restrict the upper limit of the random interval to some maximum value.\ \ Example:\ \ wait\_random\_exponential(multiplier\=0.5, \# initial window 0.5s\ max\=60) \# max 60s timeout\ \ When waiting for an unavailable resource to become available again, as opposed to trying to resolve contention for a shared resource, the wait\_exponential strategy (which uses a fixed interval) may be preferable. --- # Page not found - Read the Docs Community [tenacity.readthedocs.io](https://tenacity.readthedocs.io/) The page you requested does not exist or may have been removed. Hosted by [![Read the Docs logo](https://app-assets.readthedocs.org/readthedocsext/theme/images/logo-wordmark-dark.8035ede2e46d.svg)](https://app.readthedocs.org/) --- # Page not found - Read the Docs Community [tenacity.readthedocs.io](https://tenacity.readthedocs.io/) The page you requested does not exist or may have been removed. Hosted by [![Read the Docs logo](https://app-assets.readthedocs.org/readthedocsext/theme/images/logo-wordmark-dark.8035ede2e46d.svg)](https://app.readthedocs.org/) ---