Circuit Breaker Middleware¶
In microservices, the Circuit Breaker is used to implement a Fail Fast Model to avoid cascading failure.
The Circuit Breaker is a middleware based on purgatory.
Note
circuit breaker is not installed by default, but it is highly recommended to use it.
To use the circuit breaker, it must be added to the client factory middleware stack.
Async¶
from blacksmith import (
AsyncCircuitBreakerMiddleware,
AsyncClientFactory,
AsyncConsulDiscovery,
)
sd = AsyncConsulDiscovery()
cli = AsyncClientFactory(sd).add_middleware(
AsyncCircuitBreakerMiddleware(threshold=5, ttl=30)
)
Sync¶
from blacksmith import SyncCircuitBreaker, SyncClientFactory, SyncConsulDiscovery
sd = SyncConsulDiscovery()
cli = SyncClientFactory(sd).add_middleware(SyncCircuitBreaker(threshold=5, ttl=30))
The middleware create one circuit per client, identified by its
client_name.
If alll consecutive call to routes of that clients happen more than
the threshold
, the circuit will be open for an ellapsed time ttl (in seconds).
When the cirtuit is open, then all the incomming request will automatically
be rejected, throwing a purgatory.OpenedState.
Note
HTTPError 4xx are excluded by the circuit breaker.
By default, the circuits breaker states are stored in memory, but, it is possible to share circuit breaker state using a redis server as a storage backend.
To use a redis storage, a unit of work parameter is expected.
Async¶
from purgatory import AsyncRedisUnitOfWork
from blacksmith import AsyncCircuitBreakerMiddleware
breaker = AsyncCircuitBreakerMiddleware(
5, 30, uow=AsyncRedisUnitOfWork("redis://redis/0")
)
Important
Using redis, the middleware MUST BE initialized.
To initialize middlewares, the method blacksmith.ClientFactory.initialize()
has to be called after instantiation.
Example using initializing in an ASGI service running with hypercorn.
import asyncio
from hypercorn.asyncio import serve
from hypercorn.config import Config
import blacksmith
from notif.views import app, cli
async def main():
blacksmith.scan("notif.resources")
config = Config()
config.bind = ["0.0.0.0:8000"]
await cli.initialize()
await serve(app, config)
if __name__ == "__main__":
asyncio.run(main())
Sync¶
from purgatory import SyncRedisUnitOfWork
from blacksmith import SyncCircuitBreaker
breaker = SyncCircuitBreaker(5, 30, uow=SyncRedisUnitOfWork("redis://redis/0"))
Note
Full example of the circuit_breaker¶
You will find an example using prometheus and the circuit breaker in the examples directory: