In-memory URL backoff registry with sliding window thresholds.
Project description
url-backoff-registry
In-memory URL backoff registry with sliding window thresholds.
Track failing endpoints and back off when failures exceed a threshold within a time window. Useful for avoiding repeated requests to flaky or overloaded services.
Install
pip install url-backoff-registry
Usage
Basic usage
from url_backoff_registry import BackoffRegistry
# Back off for 120s after 3 failures within 30s
registry = BackoffRegistry(window_seconds=30, threshold=3, backoff_seconds=120)
def fetch(url):
if registry.should_backoff(url):
raise Exception(f"Backing off from {url}")
try:
response = requests.get(url)
response.raise_for_status()
return response
except Exception:
registry.record_failure(url)
raise
Decorator
Use the @track decorator to automatically record failures and clear on success:
from url_backoff_registry import BackoffError, BackoffRegistry
registry = BackoffRegistry()
@registry.track("https://api.example.com")
def fetch_data():
response = requests.get("https://api.example.com/data")
response.raise_for_status()
return response.json()
try:
data = fetch_data()
except BackoffError as e:
print(f"Backing off until {e.until}")
except requests.RequestException:
print("Request failed, failure recorded")
Per-key rules
Set different thresholds for different endpoints:
registry = BackoffRegistry(threshold=3) # Default: 3 failures
# Flaky API: back off after just 1 failure, for 5 minutes
registry.set_rule("https://flaky-api.com", threshold=1, backoff_seconds=300)
# Critical API: more lenient, 5 failures before backing off
registry.set_rule("https://critical-api.com", threshold=5)
Stats and introspection
stats = registry.stats("https://api.example.com")
# {'failures_in_window': 2, 'in_backoff': False, 'backoff_until': None}
all_keys = registry.keys()
# ['https://api.example.com', 'https://other-api.com']
API
BackoffRegistry
| Parameter | Type | Default | Description |
|---|---|---|---|
window_seconds |
int | 30 | Time window for counting failures |
threshold |
int | 3 | Number of failures to trigger backoff |
backoff_seconds |
int | 120 | How long to back off |
clock |
callable | datetime.utcnow |
Clock function (for testing) |
Methods
record_failure(key)- Record a failure for the given keyshould_backoff(key)- ReturnsTrueif currently in backoffnext_retry_at(key)- Returns datetime when backoff ends, orNoneclear(key)- Clear backoff and failure history for the keyset_rule(key, ...)- Set custom thresholds for a specific keyclear_rule(key)- Remove custom rule, revert to defaultsstats(key)- Get failure count, backoff status, and backoff end timekeys()- List all keys with recorded failures or in backofftrack(key, clear_on_success=True)- Decorator for automatic tracking
BackoffError
Raised by @track when a call is attempted while in backoff.
key- The key that is in backoffuntil- Datetime when backoff ends
FAQ
How is this different from the backoff package?
The backoff package provides decorators for retrying a single function call with exponential backoff. It's great for "retry this request up to 3 times with increasing delays."
This package solves a different problem: tracking failures across multiple calls to decide whether to attempt a request at all. It answers "should I even try this URL right now, given its recent failure history?"
backoff |
url-backoff-registry |
|
|---|---|---|
| Scope | Single function call | Cross-call state |
| Mechanism | Retry decorator | Failure registry |
| Question answered | "How many times should I retry?" | "Should I try at all?" |
They're complementary - you can use both together.
Why not just use a circuit breaker?
Circuit breakers (like pybreaker) are similar but typically operate per-function. This registry is keyed by URL/endpoint, so you can track failures for many endpoints with a single registry instance. It's lighter weight and doesn't require decorating each call site.
Development
git clone https://github.com/larsderidder/url-backoff-registry.git
cd url-backoff-registry
python -m venv .venv
. .venv/bin/activate
pip install -e ".[dev]"
pytest
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file url_backoff_registry-1.1.1.tar.gz.
File metadata
- Download URL: url_backoff_registry-1.1.1.tar.gz
- Upload date:
- Size: 6.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
807a9d9fbc6b230dff701b992f88aff68fb5f717d1e740fc848f8f5511865985
|
|
| MD5 |
e2885e4d7117b34ff2357e44179e555a
|
|
| BLAKE2b-256 |
9c2c3cc8238f0d175678d184269307c1ad5478461fb6960c00611893268b867c
|
Provenance
The following attestation bundles were made for url_backoff_registry-1.1.1.tar.gz:
Publisher:
publish.yml on larsderidder/url-backoff-registry
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
url_backoff_registry-1.1.1.tar.gz -
Subject digest:
807a9d9fbc6b230dff701b992f88aff68fb5f717d1e740fc848f8f5511865985 - Sigstore transparency entry: 871891241
- Sigstore integration time:
-
Permalink:
larsderidder/url-backoff-registry@864853ce0d9a3f3fe0878ae5d684144b64b79dab -
Branch / Tag:
refs/tags/v1.1.1 - Owner: https://github.com/larsderidder
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@864853ce0d9a3f3fe0878ae5d684144b64b79dab -
Trigger Event:
push
-
Statement type:
File details
Details for the file url_backoff_registry-1.1.1-py3-none-any.whl.
File metadata
- Download URL: url_backoff_registry-1.1.1-py3-none-any.whl
- Upload date:
- Size: 6.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0628d87564a13c18090917d5380a6ab4c6b56d182bc702f28cb919fcc12c0218
|
|
| MD5 |
1a0a8ef1ab65138e54daa127f572133e
|
|
| BLAKE2b-256 |
aa846fd080b4d45d9085b468f8dd0221dd3331196832371a4b640b0ad269e739
|
Provenance
The following attestation bundles were made for url_backoff_registry-1.1.1-py3-none-any.whl:
Publisher:
publish.yml on larsderidder/url-backoff-registry
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
url_backoff_registry-1.1.1-py3-none-any.whl -
Subject digest:
0628d87564a13c18090917d5380a6ab4c6b56d182bc702f28cb919fcc12c0218 - Sigstore transparency entry: 871891246
- Sigstore integration time:
-
Permalink:
larsderidder/url-backoff-registry@864853ce0d9a3f3fe0878ae5d684144b64b79dab -
Branch / Tag:
refs/tags/v1.1.1 - Owner: https://github.com/larsderidder
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@864853ce0d9a3f3fe0878ae5d684144b64b79dab -
Trigger Event:
push
-
Statement type: