Skip to main content

API resilience library — exponential backoff and circuit breaker

Project description

smoothapi-py

API resilience library for Python. It provides a decorator to wrap your HTTP requests with exponential backoff, full jitter, and a finite-state machine circuit breaker to protect against cascading failures.

Zero dependencies. Fully typed. Supports both sync and async functions out of the box. Automatically integrates with requests and httpx if installed.

Install

pip install smoothapi-py

Features

  • Exponential Backoff with Full Jitter: Prevents the "thundering herd" problem by randomizing retry delays.
  • Circuit Breaker (FSM): Isolated state machine (CLOSEDOPENHALF_OPEN) per decorated function. Thread-safe execution.
  • Smart Retries: Automatically detects HTTP status codes from requests and httpx exceptions. Retries on transient codes (429, 500, 502, 503, 504) and re-raises client errors immediately.
  • Graceful Fallbacks: Optionally return cached or default data instantly when the circuit is OPEN, bypassing network IO entirely.

Usage

Basic Usage (Defaults)

If you don't need custom configurations, you can instantiate the decorator with its defaults by passing an empty config object.

import requests
from smooth_api import resilient_api, ResilientConfig

# Create it with default settings
config = ResilientConfig()

@resilient_api(config)
def get_user_data(user_id: str):
    res = requests.get(f"https://api.example.com/users/{user_id}")
    res.raise_for_status() # Always raise so the decorator knows it failed!
    return res.json()

# Standard usage
try:
    data = get_user_data("123")
    print(data)
except Exception as e:
    print("Request failed completely:", e)

Default Settings provided automatically:

  • Retries: 3 attempts
  • Backoff Base Delay: 0.1 seconds (100 milliseconds)
  • Circuit Failure Threshold: Trips after 3 consecutive failures
  • Circuit Cooldown: Stays open for 10 seconds before probing
  • Status Codes to Retry: 429, 500, 502, 503, and 504

Advanced Usage (Custom Settings)

You can override any of the defaults to suit your application's needs, such as adding a fallback object.

from smooth_api import resilient_api, ResilientConfig
from smooth_api.config import BackoffConfig, CircuitBreakerConfig
import requests

config = ResilientConfig(
    backoff=BackoffConfig(
        base_delay=0.1,    # seconds to wait before first retry
        max_delay=30.0,    # cap on exponential growth
        max_retries=3      # max number of retry attempts
    ),
    circuit_breaker=CircuitBreakerConfig(
        failure_threshold=3, # trip OPEN after 3 consecutive failures
        cooldown_ms=10_000   # stay OPEN for 10 seconds before probing
    ),
    # Optional: return this exact object when the circuit is OPEN
    fallback={"status": "degraded", "data": []},
    # Optional: HTTP status codes to trigger a retry
    retry_on=[429, 500, 502, 503, 504]
)

@resilient_api(config)
def get_user_data(user_id: str):
    res = requests.get(f"https://api.example.com/users/{user_id}")
    res.raise_for_status()
    return res.json()

# You can also override the fallback at runtime per-call:
data = get_user_data("456", fallback={"status": "override"})

Async Support

The decorator automatically detects if your function is a coroutine and uses asyncio.sleep instead of blocking the thread:

import httpx

@resilient_api(config)
async def get_user_data_async(user_id: str):
    async with httpx.AsyncClient() as client:
        res = await client.get(f"https://api.example.com/users/{user_id}")
        res.raise_for_status()
        return res.json()

How It Works

  1. Isolation: The circuit breaker state is isolated per decorated function (fn.__qualname__).
  2. Circuit Check: Before execution, the breaker checks the state. If it's OPEN, the request is blocked instantly (returning your fallback, or raising RuntimeError).
  3. Execution & Retries: If an exception is raised, it attempts to extract the HTTP status code (supports requests and httpx). If the status is in retry_on, it's counted as a failure and the thread sleeps with backoff.
  4. Recovery: After cooldown_ms, the breaker enters HALF_OPEN. The next execution acts as a probe. If it succeeds, the circuit closes. If it fails, it snaps back to OPEN immediately.

License

MIT

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

smoothapi_py-0.2.0.tar.gz (6.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

smoothapi_py-0.2.0-py3-none-any.whl (6.7 kB view details)

Uploaded Python 3

File details

Details for the file smoothapi_py-0.2.0.tar.gz.

File metadata

  • Download URL: smoothapi_py-0.2.0.tar.gz
  • Upload date:
  • Size: 6.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for smoothapi_py-0.2.0.tar.gz
Algorithm Hash digest
SHA256 b64b7d4c26df2e6382b8a028c476c5afc8619cdd871a28b9a71511b9473fa425
MD5 99ef1b4684e1369c8d1e72cf615c0104
BLAKE2b-256 97b79b427640c82b1f34735c469f44cb63fab308f8909b1c4af0fe9107fc5d17

See more details on using hashes here.

File details

Details for the file smoothapi_py-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: smoothapi_py-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 6.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for smoothapi_py-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 53f90594de60512d3c71e2fba7065e751dd8237e077123a26a38ef28d590fdbf
MD5 caf18cce1f33eacb1d0add1b05b0f48c
BLAKE2b-256 eaf6f9643730034432e488ccd33568cc223c5340f2b39978ef7d771d1f0f6798

See more details on using hashes here.

Supported by

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