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!'
Raw data
{
"_id": null,
"home_page": "https://github.com/mozilla-releng/redo",
"name": "redo",
"maintainer": null,
"docs_url": null,
"requires_python": null,
"maintainer_email": null,
"keywords": null,
"author": "Ben Hearsum",
"author_email": "ben@hearsum.ca",
"download_url": "https://files.pythonhosted.org/packages/23/91/cd9b78aca21a3a5fb915582a9e8b727e2513e38732df45b2c3ee63cbe7be/redo-3.0.0.tar.gz",
"platform": null,
"description": "Redo - Utilities to retry Python callables\n==========================================\n\nIntroduction\n************\n\nRedo 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\"``).\n\nInstallation\n************\n\nFor installing with pip, run following commands\n\n::\n\n pip install redo\n\nHow To Use\n**********\n\nBelow is the list of functions available\n\n* retrier\n* retry\n* retry_async\n* retriable\n* retriable_async\n* retrying (contextmanager)\n\nretrier(attempts=5, sleeptime=10, max_sleeptime=300, sleepscale=1.5, jitter=1)\n------------------------------------------------------------------------------\n\nA 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.\n\n**Arguments Detail:** \n\n1. **attempts (int):** maximum number of times to try; defaults to 5\n2. **sleeptime (float):** how many seconds to sleep between tries; defaults to 60s (one minute)\n3. **max_sleeptime (float):** the longest we'll sleep, in seconds; defaults to 300s (five minutes)\n4. **sleepscale (float):** how much to multiply the sleep time by each iteration; defaults to 1.5\n5. **jitter (int):** random jitter to introduce to sleep time each iteration. the amount is chosen at random between ``[-jitter, +jitter]`` defaults to 1\n\n**Output:** None, a maximum of ``attempts`` number of times\n\n**Example:**\n\n::\n\n >>> n = 0\n >>> for _ in retrier(sleeptime=0, jitter=0):\n ... if n == 3:\n ... # We did the thing!\n ... break\n ... n += 1\n >>> n\n 3\n >>> n = 0\n >>> for _ in retrier(sleeptime=0, jitter=0):\n ... if n == 6:\n ... # We did the thing!\n ... break\n ... n += 1\n ... else:\n ... print(\"max tries hit\")\n max tries hit\n\nretry(action, attempts=5, sleeptime=60, max_sleeptime=5 * 60, sleepscale=1.5, jitter=1, retry_exceptions=(Exception,), cleanup=None, args=(), kwargs={}) \n--------------------------------------------------------------------------------------------------------------------------------------------------------\n\nCalls an action function until it succeeds, or we give up.\n\n**Arguments Detail:** \n\n1. **action (callable):** the function to retry\n2. **attempts (int):** maximum number of times to try; defaults to 5\n3. **sleeptime (float):** how many seconds to sleep between tries; defaults to 60s (one minute)\n4. **max_sleeptime (float):** the longest we'll sleep, in seconds; defaults to 300s (five minutes)\n5. **sleepscale (float):** how much to multiply the sleep time by each iteration; defaults to 1.5\n6. **jitter (int):** random jitter to introduce to sleep time each iteration. The amount is chosen at random between ``[-jitter, +jitter]`` defaults to 1\n7. **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.\n8. **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.\n9. **args (tuple):** positional arguments to call ``action`` with\n10. **kwargs (dict):** keyword arguments to call ``action`` with\n\n**Output:** Whatever action(\\*args, \\*\\*kwargs) returns\n \n**Output:** Whatever action(\\*args, \\*\\*kwargs) raises. ``retry_exceptions`` are caught up until the last attempt, in which case they are re-raised.\n\n**Example:**\n\n::\n\n >>> count = 0\n >>> def foo():\n ... global count\n ... count += 1\n ... print(count)\n ... if count < 3:\n ... raise ValueError(\"count is too small!\")\n ... return \"success!\"\n >>> retry(foo, sleeptime=0, jitter=0)\n 1\n 2\n 3\n 'success!'\n\nretry_async(func, attempts=5, sleeptime_callback=calculate_sleep_time, retry_exceptions=Exception, args=(), kwargs={}, sleeptime_kwargs=None)\n---------------------------------------------------------------------------------------------------------------------------------------------\n\nAn asynchronous function that retries a given async callable.\n\n**Arguments Detail:**\n\n1. **func (function):** an awaitable function to retry\n2. **attempts (int):** maximum number of attempts; defaults to 5\n3. **sleeptime_callback (function):** function to determine sleep time after each attempt; defaults to `calculateSleepTime`\n4. **retry_exceptions (list or exception):** exceptions to retry on; defaults to `Exception`\n5. **args (list):** arguments to pass to `func`\n6. **kwargs (dict):** keyword arguments to pass to `func`\n7. **sleeptime_kwargs (dict):** keyword arguments to pass to `sleeptime_callback`\n\n**Output:** The value from a successful `func` call or raises an exception after exceeding attempts.\n\n**Example:**\n\n::\n\n >>> async def async_action():\n ... # Your async code here\n >>> result = await retry_async(async_action)\n\nretriable(\\*retry_args, \\*\\*retry_kwargs)\n-----------------------------------------\n\nA decorator factory for ``retry()``. Wrap your function in ``@retriable(...)`` to give it retry powers!\n\n**Arguments Detail:** Same as for ``retry``, with the exception of ``action``, ``args``, and ``kwargs``, which are left to the normal function definition.\n\n**Output:** A function decorator\n\n**Example:**\n\n::\n\n >>> count = 0\n >>> @retriable(sleeptime=0, jitter=0)\n ... def foo():\n ... global count\n ... count += 1\n ... print(count)\n ... if count < 3:\n ... raise ValueError(\"count too small\")\n ... return \"success!\"\n >>> foo()\n 1\n 2\n 3\n 'success!'\n\nretriable_async(retry_exceptions=Exception, sleeptime_kwargs=None)\n------------------------------------------------------------------\n\nA decorator for asynchronously retrying a function.\n\n**Arguments Detail:**\n\n1. **retry_exceptions (list or exception):** exceptions to retry on; defaults to `Exception`\n2. **sleeptime_kwargs (dict):** keyword arguments to pass to the sleeptime callback\n\n**Output:** A function decorator that applies `retry_async` to the decorated function.\n\n**Example:**\n\n::\n\n >>> @retriable_async()\n ... async def async_action():\n ... # Your async code here\n >>> result = await async_action()\n\nretrying(func, \\*retry_args, \\*\\*retry_kwargs)\n----------------------------------------------\n\nA context manager for wrapping functions with retry functionality.\n\n**Arguments Detail:** \n\n1. **func (callable):** the function to wrap other arguments as per ``retry``\n\n**Output:** A context manager that returns ``retriable(func)`` on ``__enter__``\n\n**Example:**\n\n::\n\n >>> count = 0\n >>> def foo():\n ... global count\n ... count += 1\n ... print(count)\n ... if count < 3:\n ... raise ValueError(\"count too small\")\n ... return \"success!\"\n >>> with retrying(foo, sleeptime=0, jitter=0) as f:\n ... f()\n 1\n 2\n 3\n 'success!'\n",
"bugtrack_url": null,
"license": "MPL-2.0",
"summary": "Utilities to retry Python callables.",
"version": "3.0.0",
"project_urls": {
"Homepage": "https://github.com/mozilla-releng/redo"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "6467128a17272a74f56da57cbae4a6f282a29d435d080cf80714c1137192b8c9",
"md5": "54faa7ad2c302bf90434974ec723efb4",
"sha256": "66905396b2882577fa4bf7edb90fee081db2b98992d303f12e3f898ac7f7bd56"
},
"downloads": -1,
"filename": "redo-3.0.0-py2.py3-none-any.whl",
"has_sig": false,
"md5_digest": "54faa7ad2c302bf90434974ec723efb4",
"packagetype": "bdist_wheel",
"python_version": "py2.py3",
"requires_python": null,
"size": 14006,
"upload_time": "2024-07-17T18:31:12",
"upload_time_iso_8601": "2024-07-17T18:31:12.366742Z",
"url": "https://files.pythonhosted.org/packages/64/67/128a17272a74f56da57cbae4a6f282a29d435d080cf80714c1137192b8c9/redo-3.0.0-py2.py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "2391cd9b78aca21a3a5fb915582a9e8b727e2513e38732df45b2c3ee63cbe7be",
"md5": "86b4c1319a3733e07d578b477cd424e9",
"sha256": "52a14200004d6708924a547b31b7d1c717cb36b944f3a5c7b176e0d61ab81eef"
},
"downloads": -1,
"filename": "redo-3.0.0.tar.gz",
"has_sig": false,
"md5_digest": "86b4c1319a3733e07d578b477cd424e9",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 20723,
"upload_time": "2024-07-17T18:31:13",
"upload_time_iso_8601": "2024-07-17T18:31:13.739076Z",
"url": "https://files.pythonhosted.org/packages/23/91/cd9b78aca21a3a5fb915582a9e8b727e2513e38732df45b2c3ee63cbe7be/redo-3.0.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-07-17 18:31:13",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "mozilla-releng",
"github_project": "redo",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"tox": true,
"lcname": "redo"
}