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
from notif.views import app, cli

import blacksmith


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

The circuit breaker state can also be monitored using prometheus.
Take a look at the full example for usage.

Full example of the circuit_breaker#

You will find an example using prometheus and the circuit breaker in the examples directory:

../../_images/screenshot1.png