Skip to main content

retry

A simple, yet powerful, generic retry decorator in Python for retrying functions with various backoff and callback strategies.

Install

pip install retry-reloaded

Features:

  • Exception Handling: Retry based on specific exceptions. If not specified then the default behaviour is to retry on all exceptions.
  • Excluded Exceptions: Specify exceptions that should not trigger retries. If an exception listed in excluded_exceptions is raised, the retry mechanism will not retry and will raise the exception immediately. Useful use case for this is to target the generic (and default) Exception in exceptions parameter and opt-out from retrying on specific exceptions.
  • Maximum Retries: Set the maximum number of retry attempts.
  • Timeout: Specify the maximum time in seconds to spend on retries. Timeout check happens right before retry execution of the wrapped function.
  • Deadline: Define a deadline in seconds for retries to complete. Deadline check happens right after the retry execution of the wrapped function.
  • Backoff Strategies: Choose from various backoff strategies: fixed, exponential, linear, random
  • Retry Callback: Execute a callback function between retry attempts.
  • Successful Retry Callback: Perform an action after a successful retry.
  • Failure Callback: Define a callback function after failing all retries.
  • Logging control: Define which logger (or no logger) to use for logging retries and exceptions.
  • Exception Re-raising: Optionally re-raise the last original exception that occured after all retries have been exhausted.

API

  • Decorator: retry
  • Retry exceptions: MaxRetriesException, RetriesTimeoutException, RetriesDeadlineException
  • Callback factory: CallbackFactory, callback_factory
  • Backoff strategies: FixedBackOff, LinearBackOff, ExponentialBackOff, RandomUniformBackOff

Examples

# public API
from retry_reloaded import (
    retry,
    callback_factory,
    CallbackFactory,
    FixedBackOff,
    LinearBackOff,
    ExponentialBackOff,
    RandomUniformBackOff,
    MaxRetriesException,
    RetriesTimeoutException,
    RetriesDeadlineException
)
# Retry until maximum retries are reached
# no backoff strategy means the default will apply,
# which is 0 delay between retries
@retry((AssertionError,), max_retries=3)
def cause_max_retries_error():
    assert False
# Retry until timeout error after 2 seconds
# Fixed backoff strategy for 1 second delay between retries
@retry((ValueError,), timeout=2, backoff=FixedBackOff(base_delay=1))
def cause_timeout_error():
    raise ValueError
# Retry until deadline error after 3 seconds
# Not really retrying here, this will just execute once
# as the execution will take longer than deadline
@retry(deadline=3)
def cause_deadline_error():
    sleep(4)
# Retry until deadline error after 2 seconds
# Fixed backoff strategy for 1 second delay between retries
# Expected to retry twice and then succeed but restricted by deadline
@retry(
        (ValueError,),
        deadline=2,
        backoff=FixedBackOff(base_delay=1)
)
def cause_deadline_error_after_retries():
    if not hasattr(cause_deadline_error_after_retries, "call_count"):
        cause_deadline_error_after_retries.call_count = 0
    cause_deadline_error_after_retries.call_count += 1
    if cause_deadline_error_after_retries.call_count < 2:
        raise ValueError
    else:
        sleep(1)
# Retry until maximum retries are reached
# Random backoff strategy with an initial delay and
# limits for min and max delay in next retries
# Callback function between retries by passing a callable function
def retry_callback():
    logger.debug("Calling between retries")


@retry(
        (ValueError,),
        max_retries=3,
        backoff=RandomUniformBackOff(base_delay=0.3, min_delay=0.1, max_delay=0.5),
        retry_callback=retry_callback
)
def retry_with_callback():
    raise ValueError
# Retry indefinetely as there is no max retries, timeout
# or deadline specified
# Exponential backoff strategy with an initial delay of 1 second
# Parametrized callback with utility of package to call after successful retry
# Successful callback is expected after successful retry on 3rd round
def successful_retry_callback(value):
    logger.debug(f"Calling on successful retry with value: {value}")

successful_retry_callback_ = callback_factory(successful_retry_callback, "phew")

@retry(
        (ValueError,),
        backoff=ExponentialBackOff(base_delay=1),
        successful_retry_callback=successful_retry_callback_
)
def successful_retry_with_callback():
    if not hasattr(successful_retry_with_callback, "call_count"):
        successful_retry_with_callback.call_count = 0
    successful_retry_with_callback.call_count += 1
    if successful_retry_with_callback.call_count < 3:
        raise ValueError
# Retry until maximum retries are reached
# Linear backoff strategy with an initial delay of 0.1 second and 0.1 second as step
# Parametrized callback with utility of package to call after failure of all retries
# Failure callback is expected after failing all 3 retries
def failure_callback(value):
    logger.debug(f"Calling after failure of all retries with value: {value}")

failure_callback_ = CallbackFactory(failure_callback, value="wasted")

@retry(
        max_retries=3,
        backoff=LinearBackOff(base_delay=0.1, step=0.1),
        failure_callback=failure_callback_
)
def fail_with_callback():
    raise ValueError
# Retry with re-raising the original exception after all retries
# Retry 2 times and then raise the original exception (ValueError)
@retry(
        (ValueError,),
        max_retries=2,
        reraise_exception=True
)
def retry_with_reraise():
    raise ValueError("Original exception to be re-raised")
# Retry on all exceptions, except from ValueError
@retry(excluded_exceptions=(ValueError,))
def give_up_on_value_error():
    random_int = randint(1, 10)

    if random_int >= 5:
        raise RuntimeError
    else:
        raise ValueError("Give up on the error, do not retry.")

Release files for retry-reloaded 0.0.8

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for retry-reloaded 0.0.8
File Size Uploaded
retry_reloaded-0.0.8.tar.gz 13.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for retry-reloaded 0.0.8
File Interpreter ABI Platform
retry_reloaded-0.0.8-py3-none-any.whl Python 3 none any Details

Total release size: 25.4 kB

Release files / retry_reloaded-0.0.8.tar.gz

Download URL retry_reloaded-0.0.8.tar.gz
Size 13.4 kB
Tags Source
SHA-256 checksum
How to use checksums
9ed72abb0039b40cfd2bd7b8fae65d0d00cf0ef3bfcefbdb0b54e670d837ba44
BLAKE2b-256 checksum
How to use checksums
3d3c59ad0602a926a5563173a3cc882917cf0899cd06f546d71ab35baba57d59
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/5.1.1 CPython/3.12.5

Release files / retry_reloaded-0.0.8-py3-none-any.whl

Download URL retry_reloaded-0.0.8-py3-none-any.whl
Size 12.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
889df9466546495258f1b8e91e3c4242cc06f48a0d6db47908de5a9c5c256c6e
BLAKE2b-256 checksum
How to use checksums
ce405371313061dc7bf819860c1c8beda87cae5e723561022cee1799b0269bff
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/5.1.1 CPython/3.12.5

Release history Release notifications | RSS feed

This release

0.0.8 This release

2 release files

0.0.7

2 release files

0.0.6

2 release files

0.0.5

2 release files

0.0.4

2 release files

0.0.3

2 release files

0.0.2

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page