dev4py.utils.retry

The retry module provides tools to create retryable callable using exponential backoff

  1"""The `retry` module provides tools to create retryable callable using exponential backoff"""
  2
  3# Copyright 2022 the original author or authors (i.e.: St4rG00se for Dev4py).
  4#
  5# Licensed under the Apache License, Version 2.0 (the "License");
  6# you may not use this file except in compliance with the License.
  7# You may obtain a copy of the License at
  8#
  9#      https://www.apache.org/licenses/LICENSE-2.0
 10#
 11# Unless required by applicable law or agreed to in writing, software
 12# distributed under the License is distributed on an "AS IS" BASIS,
 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14# See the License for the specific language governing permissions and
 15# limitations under the License.
 16from asyncio import sleep as async_sleep
 17from dataclasses import dataclass
 18from functools import partial, wraps
 19from time import sleep
 20from typing import Callable, Awaitable, Union, Optional, cast, Any
 21
 22from dev4py.utils.objects import require_non_none, is_none
 23from dev4py.utils.types import T, P, Function
 24
 25
 26##############################
 27#     PUBLIC MODULE CLASS    #
 28##############################
 29@dataclass(frozen=True)
 30class RetryConfiguration:
 31    """
 32    RetryConfiguration class that represents a retry configuration
 33
 34    A retry configuration describes:
 35        * The maximum number of tries (first try included. I.e.: 1 means no retry on failure)
 36        * The exponential backoff elements (exponent & delay)
 37            Note: exponential backoff (/ waiting_interval) = delay * (exponent^retry_number)
 38
 39    Args:
 40        exponent (int): the exponential backoff exponent / an arbitrary multiplier to determine delay between each try
 41            (default = 2)
 42        delay (float): the exponential backoff delay in second / the initial wait for the first retry (default = 0.1)
 43        max_tries (int): max try number (first try included) (default = 3, i.e.: first try and 2 retry)
 44
 45    Raises:
 46        TypeError: if exponent or delay or max_tries is None
 47        ValueError: if exponent or delay is less than 0 or max_tries is less than 1
 48    """
 49    exponent: int = 2
 50    delay: float = 0.1  # seconds
 51    max_tries: int = 3
 52
 53    def get_waiting_interval(self, retry_number: int) -> float:
 54        """
 55        Returns the waiting interval in second in case of a retry occurs
 56        Args:
 57            retry_number: the current retry number
 58
 59        Returns:
 60            float: the waiting interval in second for the given `retry_numbers`
 61
 62        Raises:
 63            TypeError: if retry_number is None
 64            ValueError: if retry_number is lesser than or equals to 0 or retry_number greater than max_tries
 65        """
 66        if require_non_none(retry_number) <= 0:
 67            raise ValueError('retry_number must be greater than 0')
 68
 69        if retry_number > self.max_tries:
 70            raise ValueError('retry_number greater than configured max_tries')
 71
 72        return self.delay * (self.exponent ** retry_number)
 73
 74    def __post_init__(self):
 75        if require_non_none(self.exponent, "exponent must be non None") < 0:
 76            raise ValueError("exponent must be greater than or equals to 0")
 77        if require_non_none(self.delay, "delay must be non None") < 0:
 78            raise ValueError("delay must be greater than or equals to 0")
 79        if require_non_none(self.max_tries, "max_tries must be non None") < 1:
 80            raise ValueError("max_tries must be greater than or equals to 1")
 81
 82
 83##############################
 84#  PRIVATE MODULE FUNCTIONS  #
 85##############################
 86def _default_retry_on_failure(exception: BaseException) -> Any:
 87    """
 88    Default value for on_failure parameter
 89    Note: lambda are not used in order to be compatible with multiprocessing (lambda are not serializable)
 90
 91    Args:
 92        exception: The on failure exception
 93
 94    Raises:
 95        Exception: the given exception
 96    """
 97    raise exception
 98
 99
100def _with_retry(
101        sync_callable: Callable[P, T],
102        retry_config: RetryConfiguration,
103        on_failure: Function[BaseException, T],
104        retry_number: int,
105        *args: P.args,
106        **kwargs: P.kwargs
107) -> T:
108    """
109    Used to define a retryable function from `sync_callable` parameter by using the RetryConfig, on_failure and
110    retry_number parameters
111
112    Note: inner functions are not used in order to be compatible with multiprocessing
113    """
114    if retry_number > 0:
115        sleep(retry_config.get_waiting_interval(retry_number))
116
117    try:
118        return sync_callable(*args, **kwargs)
119    except BaseException as e:  # pylint: disable=W0703
120        retry_number += 1  # pragma: no mutate
121
122        if retry_number >= retry_config.max_tries:
123            return on_failure(e)
124
125        return _with_retry(sync_callable, retry_config, on_failure, retry_number, *args, **kwargs)
126
127
128async def _with_async_retry(
129        async_callable: Callable[P, Awaitable[T]],
130        retry_config: RetryConfiguration,
131        on_failure: Function[BaseException, T],
132        retry_number: int,
133        *args: P.args,
134        **kwargs: P.kwargs
135) -> T:
136    """
137    Used to define a retryable function from `async_callable` parameter by using the RetryConfig, on_failure and
138    retry_number parameters
139
140    Note: inner functions are not used in order to be compatible with multiprocessing
141    """
142    if retry_number > 0:
143        await async_sleep(retry_config.get_waiting_interval(retry_number))
144
145    try:
146        return await async_callable(*args, **kwargs)
147    except BaseException as e:  # pylint: disable=W0703
148        retry_number += 1  # pragma: no mutate
149
150        if retry_number >= retry_config.max_tries:
151            return on_failure(e)
152
153        return await _with_async_retry(async_callable, retry_config, on_failure, retry_number, *args, **kwargs)
154
155
156##############################
157#      PUBLIC FUNCTIONS      #
158##############################
159
160def retryable(
161        sync_callable: Optional[Callable[P, T]] = None,
162        retry_config: RetryConfiguration = RetryConfiguration(),
163        on_failure: Function[BaseException, T] = _default_retry_on_failure
164) -> Union[Callable[P, T], Function[Callable[P, T], Callable[P, T]]]:
165    """
166    SINCE: 3.5.0: a `to_retryable` equivalent that can also be used as decorator
167
168    Transforms a callable to a retryable one by using the given RetryConfiguration
169
170    If an error occurs when executing the returned callable the call is retried by using the given RetryConfiguration.
171    An exponential backoff is used in order to determinate the waiting time between each call. If max_tries is reached
172    then the on_failure function is called in order to return a default value or raise an exception. By default, it
173    raises the last raised exception
174
175    Args:
176        sync_callable: The callable to transform
177        retry_config: The given RetryConfiguration
178        on_failure: The action to perform if max_tries is reached (Note: can return a default value)
179
180    Returns:
181        Function[Callable[P, T], Callable[P, T]]: Corresponding to a partial `to_retryable` function filled with
182            `retry_config` and `on_failure` parameters if sync_callable is None
183
184        Callable[P, Awaitable[T]]: The retryable callable (is equivalent to `to_retryable` call) if sync_callable is not
185            None
186
187    Raises:
188        TypeError: if retry_config or on_failure is None
189    """
190    require_non_none(retry_config)
191    require_non_none(on_failure)
192
193    def _retryable_decorator(func: Callable[P, T]) -> Callable[P, T]:
194        require_non_none(func)
195
196        @wraps(func)
197        def _retryable_wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
198            return _with_retry(func, retry_config, on_failure, 0, *args, **kwargs)
199
200        return _retryable_wrapper
201
202    return _retryable_decorator if is_none(sync_callable) else _retryable_decorator(cast(Callable[P, T], sync_callable))
203
204
205def to_retryable(
206        sync_callable: Optional[Callable[P, T]] = None,
207        *,
208        retry_config: RetryConfiguration = RetryConfiguration(),
209        on_failure: Function[BaseException, T] = _default_retry_on_failure
210) -> Callable[P, T]:
211    """
212    Transforms a callable to a retryable one by using the given RetryConfiguration
213
214    If an error occurs when executing the returned callable the call is retried by using the given RetryConfiguration.
215    An exponential backoff is used in order to determinate the waiting time between each call. If max_tries is reached
216    then the on_failure function is called in order to return a default value or raise an exception. By default, it
217    raises the last raised exception
218
219    Args:
220        sync_callable: The callable to transform
221        retry_config: The given RetryConfiguration
222        on_failure: The action to perform if max_tries is reached (Note: can return a default value)
223
224    Returns:
225        Callable[P, T]: The retryable callable
226
227    Raises:
228        TypeError: if sync_callable or retry_config or on_failure is None
229    """
230    require_non_none(sync_callable)
231    require_non_none(retry_config)
232    require_non_none(on_failure)
233    return partial(_with_retry, *[sync_callable, retry_config, on_failure, 0])
234
235
236def async_retryable(
237        async_callable: Optional[Callable[P, Awaitable[T]]] = None,
238        *,
239        retry_config: RetryConfiguration = RetryConfiguration(),
240        on_failure: Function[BaseException, T] = _default_retry_on_failure
241) -> Union[Function[Callable[P, Awaitable[T]], Callable[P, Awaitable[T]]], Callable[P, Awaitable[T]]]:
242    """
243    SINCE: 3.5.0: a `to_async_retryable` equivalent that can also be used as decorator
244
245    Transforms an async callable to an async retryable one by using the given RetryConfiguration
246
247    If an error occurs when executing the returned callable the call is retried by using the given RetryConfiguration.
248    An exponential backoff is used in order to determinate the waiting time between each call. If max_tries is reached
249    then the on_failure function is called in order to return a default value or raise an exception. By default, it
250    raises the last raised exception
251
252    Args:
253        async_callable: The async callable to transform
254        retry_config: The given RetryConfiguration
255        on_failure: The action to perform if max_tries is reached (Note: can return a default value)
256
257    Returns:
258        Function[Callable[P, Awaitable[T]], Callable[P, Awaitable[T]]]: Corresponding to a partial `to_async_retryable`
259            function filled with `retry_config` and `on_failure` parameters if async_callable is None
260
261        Callable[P, Awaitable[T]]: The async retryable callable (is equivalent to `to_async_retryable` call) if
262            async_callable is not None
263
264    Raises:
265        TypeError: if retry_config or on_failure is None
266    """
267    require_non_none(retry_config)
268    require_non_none(on_failure)
269
270    def _async_retryable_decorator(func: Callable[P, Awaitable[T]]) -> Callable[P, Awaitable[T]]:
271        require_non_none(func)
272
273        @wraps(func)
274        def _async_retryable_wrapper(*args: P.args, **kwargs: P.kwargs) -> Awaitable[T]:
275            return _with_async_retry(func, retry_config, on_failure, 0, *args, **kwargs)
276
277        return _async_retryable_wrapper
278
279    return _async_retryable_decorator if is_none(async_callable) else \
280        _async_retryable_decorator(cast(Callable[P, Awaitable[T]], async_callable))
281
282
283def to_async_retryable(
284        async_callable: Callable[P, Awaitable[T]],
285        retry_config: RetryConfiguration = RetryConfiguration(),
286        on_failure: Function[BaseException, T] = _default_retry_on_failure
287) -> Callable[P, Awaitable[T]]:
288    """
289    Transforms an async callable to an async retryable one by using the given RetryConfiguration
290
291    If an error occurs when executing the returned callable the call is retried by using the given RetryConfiguration.
292    An exponential backoff is used in order to determinate the waiting time between each call. If max_tries is reached
293    then the on_failure function is called in order to return a default value or raise an exception. By default, it
294    raises the last raised exception
295
296    Args:
297        async_callable: The async callable to transform
298        retry_config: The given RetryConfiguration
299        on_failure: The action to perform if max_tries is reached (Note: can return a default value)
300
301    Returns:
302        Callable[P, Awaitable[T]]: The async retryable callable
303
304    Raises:
305        TypeError: if async_callable or retry_config or on_failure is None
306    """
307    require_non_none(async_callable)
308    require_non_none(retry_config)
309    require_non_none(on_failure)
310    return partial(_with_async_retry, *[async_callable, retry_config, on_failure, 0])
@dataclass(frozen=True)
class RetryConfiguration:
30@dataclass(frozen=True)
31class RetryConfiguration:
32    """
33    RetryConfiguration class that represents a retry configuration
34
35    A retry configuration describes:
36        * The maximum number of tries (first try included. I.e.: 1 means no retry on failure)
37        * The exponential backoff elements (exponent & delay)
38            Note: exponential backoff (/ waiting_interval) = delay * (exponent^retry_number)
39
40    Args:
41        exponent (int): the exponential backoff exponent / an arbitrary multiplier to determine delay between each try
42            (default = 2)
43        delay (float): the exponential backoff delay in second / the initial wait for the first retry (default = 0.1)
44        max_tries (int): max try number (first try included) (default = 3, i.e.: first try and 2 retry)
45
46    Raises:
47        TypeError: if exponent or delay or max_tries is None
48        ValueError: if exponent or delay is less than 0 or max_tries is less than 1
49    """
50    exponent: int = 2
51    delay: float = 0.1  # seconds
52    max_tries: int = 3
53
54    def get_waiting_interval(self, retry_number: int) -> float:
55        """
56        Returns the waiting interval in second in case of a retry occurs
57        Args:
58            retry_number: the current retry number
59
60        Returns:
61            float: the waiting interval in second for the given `retry_numbers`
62
63        Raises:
64            TypeError: if retry_number is None
65            ValueError: if retry_number is lesser than or equals to 0 or retry_number greater than max_tries
66        """
67        if require_non_none(retry_number) <= 0:
68            raise ValueError('retry_number must be greater than 0')
69
70        if retry_number > self.max_tries:
71            raise ValueError('retry_number greater than configured max_tries')
72
73        return self.delay * (self.exponent ** retry_number)
74
75    def __post_init__(self):
76        if require_non_none(self.exponent, "exponent must be non None") < 0:
77            raise ValueError("exponent must be greater than or equals to 0")
78        if require_non_none(self.delay, "delay must be non None") < 0:
79            raise ValueError("delay must be greater than or equals to 0")
80        if require_non_none(self.max_tries, "max_tries must be non None") < 1:
81            raise ValueError("max_tries must be greater than or equals to 1")

RetryConfiguration class that represents a retry configuration

A retry configuration describes:
  • The maximum number of tries (first try included. I.e.: 1 means no retry on failure)
  • The exponential backoff elements (exponent & delay) Note: exponential backoff (/ waiting_interval) = delay * (exponent^retry_number)
Arguments:
  • exponent (int): the exponential backoff exponent / an arbitrary multiplier to determine delay between each try (default = 2)
  • delay (float): the exponential backoff delay in second / the initial wait for the first retry (default = 0.1)
  • max_tries (int): max try number (first try included) (default = 3, i.e.: first try and 2 retry)
Raises:
  • TypeError: if exponent or delay or max_tries is None
  • ValueError: if exponent or delay is less than 0 or max_tries is less than 1
RetryConfiguration(exponent: int = 2, delay: float = 0.1, max_tries: int = 3)
exponent: int = 2
delay: float = 0.1
max_tries: int = 3
def get_waiting_interval(self, retry_number: int) -> float:
54    def get_waiting_interval(self, retry_number: int) -> float:
55        """
56        Returns the waiting interval in second in case of a retry occurs
57        Args:
58            retry_number: the current retry number
59
60        Returns:
61            float: the waiting interval in second for the given `retry_numbers`
62
63        Raises:
64            TypeError: if retry_number is None
65            ValueError: if retry_number is lesser than or equals to 0 or retry_number greater than max_tries
66        """
67        if require_non_none(retry_number) <= 0:
68            raise ValueError('retry_number must be greater than 0')
69
70        if retry_number > self.max_tries:
71            raise ValueError('retry_number greater than configured max_tries')
72
73        return self.delay * (self.exponent ** retry_number)

Returns the waiting interval in second in case of a retry occurs

Arguments:
  • retry_number: the current retry number
Returns:

float: the waiting interval in second for the given retry_numbers

Raises:
  • TypeError: if retry_number is None
  • ValueError: if retry_number is lesser than or equals to 0 or retry_number greater than max_tries
def retryable( sync_callable: Optional[Callable[~P, ~T]] = None, retry_config: RetryConfiguration = RetryConfiguration(exponent=2, delay=0.1, max_tries=3), on_failure: Callable[[BaseException], ~T] = <function _default_retry_on_failure>) -> Union[Callable[~P, ~T], Callable[[Callable[~P, ~T]], Callable[~P, ~T]]]:
161def retryable(
162        sync_callable: Optional[Callable[P, T]] = None,
163        retry_config: RetryConfiguration = RetryConfiguration(),
164        on_failure: Function[BaseException, T] = _default_retry_on_failure
165) -> Union[Callable[P, T], Function[Callable[P, T], Callable[P, T]]]:
166    """
167    SINCE: 3.5.0: a `to_retryable` equivalent that can also be used as decorator
168
169    Transforms a callable to a retryable one by using the given RetryConfiguration
170
171    If an error occurs when executing the returned callable the call is retried by using the given RetryConfiguration.
172    An exponential backoff is used in order to determinate the waiting time between each call. If max_tries is reached
173    then the on_failure function is called in order to return a default value or raise an exception. By default, it
174    raises the last raised exception
175
176    Args:
177        sync_callable: The callable to transform
178        retry_config: The given RetryConfiguration
179        on_failure: The action to perform if max_tries is reached (Note: can return a default value)
180
181    Returns:
182        Function[Callable[P, T], Callable[P, T]]: Corresponding to a partial `to_retryable` function filled with
183            `retry_config` and `on_failure` parameters if sync_callable is None
184
185        Callable[P, Awaitable[T]]: The retryable callable (is equivalent to `to_retryable` call) if sync_callable is not
186            None
187
188    Raises:
189        TypeError: if retry_config or on_failure is None
190    """
191    require_non_none(retry_config)
192    require_non_none(on_failure)
193
194    def _retryable_decorator(func: Callable[P, T]) -> Callable[P, T]:
195        require_non_none(func)
196
197        @wraps(func)
198        def _retryable_wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
199            return _with_retry(func, retry_config, on_failure, 0, *args, **kwargs)
200
201        return _retryable_wrapper
202
203    return _retryable_decorator if is_none(sync_callable) else _retryable_decorator(cast(Callable[P, T], sync_callable))

SINCE: 3.5.0: a to_retryable equivalent that can also be used as decorator

Transforms a callable to a retryable one by using the given RetryConfiguration

If an error occurs when executing the returned callable the call is retried by using the given RetryConfiguration. An exponential backoff is used in order to determinate the waiting time between each call. If max_tries is reached then the on_failure function is called in order to return a default value or raise an exception. By default, it raises the last raised exception

Arguments:
  • sync_callable: The callable to transform
  • retry_config: The given RetryConfiguration
  • on_failure: The action to perform if max_tries is reached (Note: can return a default value)
Returns:

Function[Callable[P, T], Callable[P, T]]: Corresponding to a partial to_retryable function filled with retry_config and on_failure parameters if sync_callable is None

Callable[P, Awaitable[T]]: The retryable callable (is equivalent to to_retryable call) if sync_callable is not None

Raises:
  • TypeError: if retry_config or on_failure is None
def to_retryable( sync_callable: Optional[Callable[~P, ~T]] = None, *, retry_config: RetryConfiguration = RetryConfiguration(exponent=2, delay=0.1, max_tries=3), on_failure: Callable[[BaseException], ~T] = <function _default_retry_on_failure>) -> Callable[~P, ~T]:
206def to_retryable(
207        sync_callable: Optional[Callable[P, T]] = None,
208        *,
209        retry_config: RetryConfiguration = RetryConfiguration(),
210        on_failure: Function[BaseException, T] = _default_retry_on_failure
211) -> Callable[P, T]:
212    """
213    Transforms a callable to a retryable one by using the given RetryConfiguration
214
215    If an error occurs when executing the returned callable the call is retried by using the given RetryConfiguration.
216    An exponential backoff is used in order to determinate the waiting time between each call. If max_tries is reached
217    then the on_failure function is called in order to return a default value or raise an exception. By default, it
218    raises the last raised exception
219
220    Args:
221        sync_callable: The callable to transform
222        retry_config: The given RetryConfiguration
223        on_failure: The action to perform if max_tries is reached (Note: can return a default value)
224
225    Returns:
226        Callable[P, T]: The retryable callable
227
228    Raises:
229        TypeError: if sync_callable or retry_config or on_failure is None
230    """
231    require_non_none(sync_callable)
232    require_non_none(retry_config)
233    require_non_none(on_failure)
234    return partial(_with_retry, *[sync_callable, retry_config, on_failure, 0])

Transforms a callable to a retryable one by using the given RetryConfiguration

If an error occurs when executing the returned callable the call is retried by using the given RetryConfiguration. An exponential backoff is used in order to determinate the waiting time between each call. If max_tries is reached then the on_failure function is called in order to return a default value or raise an exception. By default, it raises the last raised exception

Arguments:
  • sync_callable: The callable to transform
  • retry_config: The given RetryConfiguration
  • on_failure: The action to perform if max_tries is reached (Note: can return a default value)
Returns:

Callable[P, T]: The retryable callable

Raises:
  • TypeError: if sync_callable or retry_config or on_failure is None
def async_retryable( async_callable: Optional[Callable[~P, Awaitable[~T]]] = None, *, retry_config: RetryConfiguration = RetryConfiguration(exponent=2, delay=0.1, max_tries=3), on_failure: Callable[[BaseException], ~T] = <function _default_retry_on_failure>) -> Union[Callable[[Callable[~P, Awaitable[~T]]], Callable[~P, Awaitable[~T]]], Callable[~P, Awaitable[~T]]]:
237def async_retryable(
238        async_callable: Optional[Callable[P, Awaitable[T]]] = None,
239        *,
240        retry_config: RetryConfiguration = RetryConfiguration(),
241        on_failure: Function[BaseException, T] = _default_retry_on_failure
242) -> Union[Function[Callable[P, Awaitable[T]], Callable[P, Awaitable[T]]], Callable[P, Awaitable[T]]]:
243    """
244    SINCE: 3.5.0: a `to_async_retryable` equivalent that can also be used as decorator
245
246    Transforms an async callable to an async retryable one by using the given RetryConfiguration
247
248    If an error occurs when executing the returned callable the call is retried by using the given RetryConfiguration.
249    An exponential backoff is used in order to determinate the waiting time between each call. If max_tries is reached
250    then the on_failure function is called in order to return a default value or raise an exception. By default, it
251    raises the last raised exception
252
253    Args:
254        async_callable: The async callable to transform
255        retry_config: The given RetryConfiguration
256        on_failure: The action to perform if max_tries is reached (Note: can return a default value)
257
258    Returns:
259        Function[Callable[P, Awaitable[T]], Callable[P, Awaitable[T]]]: Corresponding to a partial `to_async_retryable`
260            function filled with `retry_config` and `on_failure` parameters if async_callable is None
261
262        Callable[P, Awaitable[T]]: The async retryable callable (is equivalent to `to_async_retryable` call) if
263            async_callable is not None
264
265    Raises:
266        TypeError: if retry_config or on_failure is None
267    """
268    require_non_none(retry_config)
269    require_non_none(on_failure)
270
271    def _async_retryable_decorator(func: Callable[P, Awaitable[T]]) -> Callable[P, Awaitable[T]]:
272        require_non_none(func)
273
274        @wraps(func)
275        def _async_retryable_wrapper(*args: P.args, **kwargs: P.kwargs) -> Awaitable[T]:
276            return _with_async_retry(func, retry_config, on_failure, 0, *args, **kwargs)
277
278        return _async_retryable_wrapper
279
280    return _async_retryable_decorator if is_none(async_callable) else \
281        _async_retryable_decorator(cast(Callable[P, Awaitable[T]], async_callable))

SINCE: 3.5.0: a to_async_retryable equivalent that can also be used as decorator

Transforms an async callable to an async retryable one by using the given RetryConfiguration

If an error occurs when executing the returned callable the call is retried by using the given RetryConfiguration. An exponential backoff is used in order to determinate the waiting time between each call. If max_tries is reached then the on_failure function is called in order to return a default value or raise an exception. By default, it raises the last raised exception

Arguments:
  • async_callable: The async callable to transform
  • retry_config: The given RetryConfiguration
  • on_failure: The action to perform if max_tries is reached (Note: can return a default value)
Returns:

Function[Callable[P, Awaitable[T]], Callable[P, Awaitable[T]]]: Corresponding to a partial to_async_retryable function filled with retry_config and on_failure parameters if async_callable is None

Callable[P, Awaitable[T]]: The async retryable callable (is equivalent to to_async_retryable call) if async_callable is not None

Raises:
  • TypeError: if retry_config or on_failure is None
def to_async_retryable( async_callable: Callable[~P, Awaitable[~T]], retry_config: RetryConfiguration = RetryConfiguration(exponent=2, delay=0.1, max_tries=3), on_failure: Callable[[BaseException], ~T] = <function _default_retry_on_failure>) -> Callable[~P, Awaitable[~T]]:
284def to_async_retryable(
285        async_callable: Callable[P, Awaitable[T]],
286        retry_config: RetryConfiguration = RetryConfiguration(),
287        on_failure: Function[BaseException, T] = _default_retry_on_failure
288) -> Callable[P, Awaitable[T]]:
289    """
290    Transforms an async callable to an async retryable one by using the given RetryConfiguration
291
292    If an error occurs when executing the returned callable the call is retried by using the given RetryConfiguration.
293    An exponential backoff is used in order to determinate the waiting time between each call. If max_tries is reached
294    then the on_failure function is called in order to return a default value or raise an exception. By default, it
295    raises the last raised exception
296
297    Args:
298        async_callable: The async callable to transform
299        retry_config: The given RetryConfiguration
300        on_failure: The action to perform if max_tries is reached (Note: can return a default value)
301
302    Returns:
303        Callable[P, Awaitable[T]]: The async retryable callable
304
305    Raises:
306        TypeError: if async_callable or retry_config or on_failure is None
307    """
308    require_non_none(async_callable)
309    require_non_none(retry_config)
310    require_non_none(on_failure)
311    return partial(_with_async_retry, *[async_callable, retry_config, on_failure, 0])

Transforms an async callable to an async retryable one by using the given RetryConfiguration

If an error occurs when executing the returned callable the call is retried by using the given RetryConfiguration. An exponential backoff is used in order to determinate the waiting time between each call. If max_tries is reached then the on_failure function is called in order to return a default value or raise an exception. By default, it raises the last raised exception

Arguments:
  • async_callable: The async callable to transform
  • retry_config: The given RetryConfiguration
  • on_failure: The action to perform if max_tries is reached (Note: can return a default value)
Returns:

Callable[P, Awaitable[T]]: The async retryable callable

Raises:
  • TypeError: if async_callable or retry_config or on_failure is None