cliffracer-resilience
Circuit breaking and rate limiting for Cliffracer microservices.
Overview
High-throughput microservices need to protect themselves from cascading failures and traffic spikes:
- Circuit Breaking: When a downstream dependency fails repeatedly, requests fail fast locally without sending wire traffic, giving the downstream service time to recover.
- Rate Limiting: Enforces call rate thresholds per handler or per key using in-memory or distributed NATS KV sliding window algorithms, rejecting excess requests over the wire via clean
RpcRefusedresponses.
Features
Circuit Breaker
- State Machine:
CLOSED->OPEN->HALF-OPEN->CLOSED. - Fast Fail: When in
OPENstate, requests raiseRpcCircuitOpenErrorlocally without placing messages on the NATS wire. - Cooldown & Probing: After
recovery_timeout, transitions toHALF_OPENto permit a probe request. Success resets toCLOSED; failure trips back toOPEN. - Integration: Replaces standard
RpcProxywithResilientRpcProxy.
Rate Limiting
@rate_limit(calls=100, window=60)Decorator: Declare call limits per time window directly on RPC and event handlers.- Dual Backends:
InMemoryRateLimiter: Local sliding window using timestamp queues with concurrency locks.KvRateLimiter: Distributed sliding window using NATS JetStream KV store with optimistic concurrency and automatic in-memory fallback.
- Wire Refusal: Excess calls raise
RateLimitExceeded(RejectMessage)which the Cliffracer container translates to wire error{"error": "refused: rate limit exceeded"}, surfacing asRpcRefusedon the client. - Extension:
ResilienceExtensionenforces rate limits in theworker_setuphook before handlers execute.
Usage
1. Resilient RPC Proxy (Circuit Breaker)
from cliffracer import CliffracerService, rpc
from cliffracer_resilience import ResilientRpcProxy, CircuitBreakerConfig
class OrderService(CliffracerService):
# Protect outbound calls to payment service
payment = ResilientRpcProxy(
"payment_service",
config=CircuitBreakerConfig(
failure_threshold=5,
recovery_timeout=30.0,
half_open_max_calls=1,
),
)
@rpc
async def process_order(self, order_id: str, amount: float) -> dict[str, str]:
# Fails fast locally with RpcCircuitOpenError if payment service is down
result = await self.payment.charge(order_id=order_id, amount=amount)
return {"status": "paid", "result": result}
2. Handler Rate Limiting
from cliffracer import CliffracerService, rpc
from cliffracer_resilience import ResilienceExtension, rate_limit
class ApiService(CliffracerService):
resilience = ResilienceExtension()
@rpc
@rate_limit(calls=10, window=60.0)
async def heavy_operation(self, query: str) -> dict[str, str]:
return {"result": f"processed {query}"}
@rpc
@rate_limit(calls=5, window=1.0, key=lambda ctx: ctx.payload.get("user_id", "anon"))
async def user_operation(self, user_id: str) -> dict[str, str]:
return {"user": user_id}
3. Distributed Rate Limiter with NATS KV
from cliffracer import CliffracerService, rpc
from cliffracer_resilience import ResilienceExtension, KvRateLimiter, rate_limit
class DistributedService(CliffracerService):
resilience = ResilienceExtension(limiter=KvRateLimiter(bucket_name="rate_limits"))
@rpc
@rate_limit(calls=100, window=60.0)
async def shared_endpoint(self) -> str:
return "success"
Metadata
Release files for cliffracer-resilience 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| cliffracer_resilience-1.0.0.tar.gz | 16.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| cliffracer_resilience-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 28.9 kB
Release files / cliffracer_resilience-1.0.0.tar.gz
| Download URL | cliffracer_resilience-1.0.0.tar.gz |
|---|---|
| Size | 16.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6dc3f8b28bc27b9e53fa234e61d4ecdbbeb93ccfb99863688cb58d2d683e9e4c
|
|
BLAKE2b-256 checksum How to use checksums |
01456d30b3e8b72ef6d75aca75ad228b6692c4ae9736e94443a8ce22c22fcb11
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / cliffracer_resilience-1.0.0-py3-none-any.whl
| Download URL | cliffracer_resilience-1.0.0-py3-none-any.whl |
|---|---|
| Size | 12.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
608e70d8edd035725a4a287d8381f075dbfe038e514ad72ced78d70c3149eb67
|
|
BLAKE2b-256 checksum How to use checksums |
358c9c172d1ce06fa0f88d4cf155158536e74b21cddfa05816967bff6ce6402c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|