Skip to main content

A generic retry package for Python

Project description

Retry Package

A generic retry package for Python.

Features

  • Generic Decorator API
  • Specify stop condition (e.g., limit by number of attempts, time-based conditions)
  • Specify wait condition (e.g., exponential backoff, fixed delay, random delay)
  • Customize retrying on Exceptions
  • Customize retrying on expected returned result
  • Retry on coroutines
  • Retry code block with context manager
  • Logging and custom callbacks before/after retries and before sleep
  • Retry statistics and dynamic arguments at runtime

Installation

pip install retry_plus

Usage

For detailed usage and examples, refer to the Conditions Documentation.

Synchronous Function

from retry import Retry, stop_after_attempt, wait_exponential
import time

@Retry(
    stop_condition=stop_after_attempt(5),
    wait_condition=wait_exponential(multiplier=1, min_wait=1, max_wait=10),
    retry_on_exceptions=(ValueError,),
    retry_on_result=lambda result: result != "Success"
)
def unreliable_sync_function():
    print("Trying to perform an unreliable operation.")
    if time.time() % 2 < 1:
        raise ValueError("Simulated transient error.")
    return "Success"

try:
    result = unreliable_sync_function()
    print(f"Function succeeded with result: {result}")
except Exception as e:
    print(f"Function failed after retries with exception: {e}")

Asynchronous Function

import asyncio
from retry import Retry, stop_after_attempt, wait_exponential
import time

@Retry(
    stop_condition=stop_after_attempt(5),
    wait_condition=wait_exponential(multiplier=1, min_wait=1, max_wait=10),
    retry_on_exceptions=(ValueError,),
    retry_on_result=lambda result: result != "Success"
)
async def unreliable_async_function():
    print("Trying to perform an unreliable operation.")
    if time.time() % 2 < 1:
        raise ValueError("Simulated transient error.")
    return "Success"

async def main():
    try:
        result = await unreliable_async_function()
        print(f"Function succeeded with result: {result}")
    except Exception as e:
        print(f"Function failed after retries with exception: {e}")

asyncio.run(main())

Context Manager

from retry import Retry, stop_after_attempt, wait_exponential
import time

try:
    with Retry(
            stop_condition=stop_after_attempt(3),
            wait_condition=wait_exponential(multiplier=1, min_wait=1, max_wait=5),
            retry_on_exceptions=(ValueError,)
    ):
        print("Trying block operation.")
        if time.time() % 2 < 1:
            raise ValueError("Simulated transient error.")
        print("Block operation succeeded.")
except Exception as e:
    print(f"Context manager failed after retries with exception: {e}")

Advanced Usage

Combining Stop and Wait Conditions

from retry import Retry, stop_after_delay, wait_random_exponential
import time

@Retry(
    stop_condition=stop_after_delay(20),  # Stop after 20 seconds
    wait_condition=wait_random_exponential(multiplier=1, max_seconds=10),  # Exponential backoff with randomness
    retry_on_exceptions=(ValueError,)
)
def unreliable_function():
    print("Trying to perform an unreliable operation.")
    if time.time() % 2 < 1:
        raise ValueError("Simulated transient error.")
    return "Success"

try:
    result = unreliable_function()
    print(f"Function succeeded with result: {result}")
except Exception as e:
    print(f"Function failed after retries with exception: {e}")

Real Example for http requests

import requests
from retry import Retry, stop_after_attempt, wait_exponential

# Define a function to make an HTTP request
@Retry(
    stop_condition=stop_after_attempt(5),  # Retry up to 5 times
    wait_condition=wait_exponential(multiplier=1, min_wait=1, max_wait=10),  # Exponential backoff
    retry_on_exceptions=(requests.RequestException,),  # Retry on any requests exception
    retry_on_result=lambda result: result.status_code != 200  # Retry if the status code is not 200
)
def fetch_data_from_api(url):
    print(f"Trying to fetch data from {url}")
    response = requests.get(url)
    response.raise_for_status()  # Raise an HTTPError on bad status
    return response

# Use the function with a simulated unreliable endpoint
try:
    # Simulating a service that returns 500 Internal Server Error 50% of the time
    data = fetch_data_from_api("https://httpbin.org/status/500")
    print("Data fetched successfully:", data)
except Exception as e:
    print(f"Failed to fetch data after retries. Error: {e}")

# Use the function with a simulated successful endpoint
try:
    # Simulating a service that returns 200 OK
    data = fetch_data_from_api("https://httpbin.org/status/200")
    print("Data fetched successfully:", data)
except Exception as e:
    print(f"Failed to fetch data after retries. Error: {e}")

Default Conditions

If stop_condition and wait_condition are not provided, the following defaults will be used:

  • Stop Condition: Stops after 3 attempts.
  • Wait Condition: Waits 1 second between attempts.
from retry import Retry
import time

@Retry()
def default_unreliable_function():
    print("Trying to perform an unreliable operation.")
    if time.time() % 2 < 1:
        raise ValueError("Simulated transient error.")
    return "Success"

try:
    result = default_unreliable_function()
    print(f"Function succeeded with result: {result}")
except Exception as e:
    print(f"Function failed after retries with exception: {e}")

Tests

To run the tests, use pytest:

pytest

These tests cover:

  • Synchronous and Asynchronous Functions: Testing both sync and async functions with various retry conditions.
  • Fixed and Random Wait Conditions: Verifying the correct behavior with fixed and random wait conditions.
  • Exponential Backoff: Ensuring that the retry logic respects exponential backoff settings.
  • Combined Stop Conditions: Combining multiple stop conditions and ensuring the retry logic works as expected.
  • Context Manager: Testing the retry logic within a context manager.
  • Exception Type and Result Conditions: Verifying that the retry logic correctly handles retries based on specific exception types and result values.

Contribute

We welcome contributions to improve the retry package. Here are some ways you can contribute:

  1. Report Bugs: If you find a bug, please report it using the GitHub issue tracker.
  2. Feature Requests: If you have an idea for a new feature, please open an issue to discuss it.
  3. Submit Pull Requests: If you have a fix or a new feature, please submit a pull request.

How to Contribute

  1. Fork the repository: Click the "Fork" button on the GitHub repository page.
  2. Clone your fork: Clone your fork to your local machine.
    git clone https://github.com/talaatmagdyx/retry_plus.git
    
  3. Create a branch: Create a new branch for your changes.
    git checkout -b my-new-feature
    
  4. Make your changes: Make your changes to the code.
  5. Commit your changes: Commit your changes with a descriptive commit message.
    git commit -am 'Add some feature'
    
  6. Push to the branch: Push your changes to your fork.
    git push origin my-new-feature
    
  7. Create a pull request: Go to the GitHub repository page and create a pull request from your fork.

Changelog

All notable changes to this project will be documented in this section.

[Unreleased]

Added

  • Initial release of the retry package.
  • Generic decorator API for retrying operations.
  • Support for synchronous and asynchronous functions.
  • Various stop conditions (e.g., number of attempts, time-based).
  • Various wait conditions (e.g., exponential backoff, fixed delay, random delay).
  • Customizable retry conditions based on exceptions and result values.
  • Context manager support.
  • Logging and custom callbacks before/after retries and before sleep.
  • Retry statistics and dynamic arguments at runtime.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

retry_plus-1.0.5.tar.gz (12.3 kB view details)

Uploaded Source

Built Distribution

retry_plus-1.0.5-py3-none-any.whl (13.6 kB view details)

Uploaded Python 3

File details

Details for the file retry_plus-1.0.5.tar.gz.

File metadata

  • Download URL: retry_plus-1.0.5.tar.gz
  • Upload date:
  • Size: 12.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.0 CPython/3.11.4

File hashes

Hashes for retry_plus-1.0.5.tar.gz
Algorithm Hash digest
SHA256 466a4d600d33a25f1c3e7177a34689d466e0fc1332701b72b3e788c04dc3dc19
MD5 129e2e47462448b9cc0c332fa90eab99
BLAKE2b-256 068cc550ff12c0adcb1f5258e8a002c7ff72fca0c3701b48b61ed2127ae0b004

See more details on using hashes here.

File details

Details for the file retry_plus-1.0.5-py3-none-any.whl.

File metadata

  • Download URL: retry_plus-1.0.5-py3-none-any.whl
  • Upload date:
  • Size: 13.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.0 CPython/3.11.4

File hashes

Hashes for retry_plus-1.0.5-py3-none-any.whl
Algorithm Hash digest
SHA256 24bc3f4bea0de626c2405159325f7f6a45c3de111ae2360ddaea71d91bd0f48c
MD5 887633264996bbcb5eeac950e6be7960
BLAKE2b-256 f1b37f6d52e992cda90db4877d079f2acff833cd59aac592ce4b8385a7a1ea01

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page