Metadata-Version: 2.1 Name: redo Version: 3.0.0 Summary: Utilities to retry Python callables. Home-page: https://github.com/mozilla-releng/redo Author: Ben Hearsum Author-email: ben@hearsum.ca License: MPL-2.0 Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0) Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 License-File: LICENSE License-File: AUTHORS Redo - Utilities to retry Python callables ========================================== Introduction ************ Redo provides various means to add seamless ability to retry to any Python callable. Redo includes plain functions (``redo.retry``, ``redo.retry_async``), decorators (``redo.retriable``, ``redo.retriable_async``), and a context manager (``redo.retrying``) to enable you to integrate it in the best possible way for your project. As a bonus, a standalone interface is also included (``"retry"``). Installation ************ For installing with pip, run following commands :: pip install redo How To Use ********** Below is the list of functions available * retrier * retry * retry_async * retriable * retriable_async * retrying (contextmanager) retrier(attempts=5, sleeptime=10, max_sleeptime=300, sleepscale=1.5, jitter=1) ------------------------------------------------------------------------------ A generator function that sleeps between retries, handles exponential back off and jitter. The action you are retrying is meant to run after retrier yields. At each iteration, we sleep for ``sleeptime + random.randint(-jitter, jitter)``. Afterwards sleeptime is multiplied by sleepscale for the next iteration. **Arguments Detail:** 1. **attempts (int):** maximum number of times to try; defaults to 5 2. **sleeptime (float):** how many seconds to sleep between tries; defaults to 60s (one minute) 3. **max_sleeptime (float):** the longest we'll sleep, in seconds; defaults to 300s (five minutes) 4. **sleepscale (float):** how much to multiply the sleep time by each iteration; defaults to 1.5 5. **jitter (int):** random jitter to introduce to sleep time each iteration. the amount is chosen at random between ``[-jitter, +jitter]`` defaults to 1 **Output:** None, a maximum of ``attempts`` number of times **Example:** :: >>> n = 0 >>> for _ in retrier(sleeptime=0, jitter=0): ... if n == 3: ... # We did the thing! ... break ... n += 1 >>> n 3 >>> n = 0 >>> for _ in retrier(sleeptime=0, jitter=0): ... if n == 6: ... # We did the thing! ... break ... n += 1 ... else: ... print("max tries hit") max tries hit retry(action, attempts=5, sleeptime=60, max_sleeptime=5 * 60, sleepscale=1.5, jitter=1, retry_exceptions=(Exception,), cleanup=None, args=(), kwargs={}) -------------------------------------------------------------------------------------------------------------------------------------------------------- Calls an action function until it succeeds, or we give up. **Arguments Detail:** 1. **action (callable):** the function to retry 2. **attempts (int):** maximum number of times to try; defaults to 5 3. **sleeptime (float):** how many seconds to sleep between tries; defaults to 60s (one minute) 4. **max_sleeptime (float):** the longest we'll sleep, in seconds; defaults to 300s (five minutes) 5. **sleepscale (float):** how much to multiply the sleep time by each iteration; defaults to 1.5 6. **jitter (int):** random jitter to introduce to sleep time each iteration. The amount is chosen at random between ``[-jitter, +jitter]`` defaults to 1 7. **retry_exceptions (tuple):** tuple of exceptions to be caught. If other exceptions are raised by ``action()``, then these are immediately re-raised to the caller. 8. **cleanup (callable):** optional; called if one of ``retry_exceptions`` is caught. No arguments are passed to the cleanup function; if your cleanup requires arguments, consider using ``functools.partial`` or a ``lambda`` function. 9. **args (tuple):** positional arguments to call ``action`` with 10. **kwargs (dict):** keyword arguments to call ``action`` with **Output:** Whatever action(\*args, \*\*kwargs) returns **Output:** Whatever action(\*args, \*\*kwargs) raises. ``retry_exceptions`` are caught up until the last attempt, in which case they are re-raised. **Example:** :: >>> count = 0 >>> def foo(): ... global count ... count += 1 ... print(count) ... if count < 3: ... raise ValueError("count is too small!") ... return "success!" >>> retry(foo, sleeptime=0, jitter=0) 1 2 3 'success!' retry_async(func, attempts=5, sleeptime_callback=calculate_sleep_time, retry_exceptions=Exception, args=(), kwargs={}, sleeptime_kwargs=None) --------------------------------------------------------------------------------------------------------------------------------------------- An asynchronous function that retries a given async callable. **Arguments Detail:** 1. **func (function):** an awaitable function to retry 2. **attempts (int):** maximum number of attempts; defaults to 5 3. **sleeptime_callback (function):** function to determine sleep time after each attempt; defaults to `calculateSleepTime` 4. **retry_exceptions (list or exception):** exceptions to retry on; defaults to `Exception` 5. **args (list):** arguments to pass to `func` 6. **kwargs (dict):** keyword arguments to pass to `func` 7. **sleeptime_kwargs (dict):** keyword arguments to pass to `sleeptime_callback` **Output:** The value from a successful `func` call or raises an exception after exceeding attempts. **Example:** :: >>> async def async_action(): ... # Your async code here >>> result = await retry_async(async_action) retriable(\*retry_args, \*\*retry_kwargs) ----------------------------------------- A decorator factory for ``retry()``. Wrap your function in ``@retriable(...)`` to give it retry powers! **Arguments Detail:** Same as for ``retry``, with the exception of ``action``, ``args``, and ``kwargs``, which are left to the normal function definition. **Output:** A function decorator **Example:** :: >>> count = 0 >>> @retriable(sleeptime=0, jitter=0) ... def foo(): ... global count ... count += 1 ... print(count) ... if count < 3: ... raise ValueError("count too small") ... return "success!" >>> foo() 1 2 3 'success!' retriable_async(retry_exceptions=Exception, sleeptime_kwargs=None) ------------------------------------------------------------------ A decorator for asynchronously retrying a function. **Arguments Detail:** 1. **retry_exceptions (list or exception):** exceptions to retry on; defaults to `Exception` 2. **sleeptime_kwargs (dict):** keyword arguments to pass to the sleeptime callback **Output:** A function decorator that applies `retry_async` to the decorated function. **Example:** :: >>> @retriable_async() ... async def async_action(): ... # Your async code here >>> result = await async_action() retrying(func, \*retry_args, \*\*retry_kwargs) ---------------------------------------------- A context manager for wrapping functions with retry functionality. **Arguments Detail:** 1. **func (callable):** the function to wrap other arguments as per ``retry`` **Output:** A context manager that returns ``retriable(func)`` on ``__enter__`` **Example:** :: >>> count = 0 >>> def foo(): ... global count ... count += 1 ... print(count) ... if count < 3: ... raise ValueError("count too small") ... return "success!" >>> with retrying(foo, sleeptime=0, jitter=0) as f: ... f() 1 2 3 'success!'