A sync/async circuit breaker implementation
Project description
Lasier
A sync/async circuit breaker implementation
According to Nygard on your masterpiece book Release It!:
[...] circuit breakers protect overeager gadget hounds from burning their houses down. The principle is the same: detect excess usage, fail first, and open the circuit. More abstractly, the circuit breaker exists to allow one subsystem (an electrical circuit) to fail (excessive current draw, possibly from a short circuit) without destroying the entire system (the house). Furthermore, once the danger has passed, the circuit breaker can be reset to restore full function to the system.
Requirements
- Python >= 3.7
Instalation
Using pip
:
pip install lasier
Usage
To use lasier circuit breaker you'll need a rule
and a cache
(the circuit state storage) instance
Rule
A Rule
is the mechanism that define where circuit will open or close.
MaxFailuresRule
Rule to open circuit based on maximum number of failures
from lasier.circuit_breaker.rules import MaxFailuresRule
rule = MaxFailuresRule(
max_failures=500,
failure_cache_key='my_cb'
)
Arguments
Argument | Definition |
---|---|
max_failures | Maximum number of errors |
failure_cache_key | Cache key where the number of errors is incremented |
PercentageFailuresRule
Rule to open circuit based on a percentage of failures
from lasier.circuit_breaker.rules import PercentageFailuresRule
rule = PercentageFailuresRule(
max_failures_percentage=60,
failure_cache_key='my_cb',
min_accepted_requests=100,
request_cache_key='my_cb_request'
)
Arguments
Argument | Definition |
---|---|
max_failures_percentage | Maximum percentage of errors |
failure_cache_key | Cache key where the number of errors is incremented |
min_accepted_requests | Minimum number of requests accepted to not open circuit breaker |
request_cache_key | Cache key where the number of requests is incremented |
Circuit Breaker
You can use the Lasier circuit breaker with a context_manager f.ex:
from lasier.circuit_breaker.sync import CircuitBreaker
...
def some_protected_func():
with CircuitBreaker(
rule=rule,
cache=cache,
failure_exception=ValueError,
catch_exceptions=(KeyError, TypeError)
):
# some process
Or a decorator, f.ex:
from lasier.circuit_breaker.asyncio import circuit_breaker
...
@circuit_breaker(
rule=rule,
cache=cache,
failure_exception=ValueError,
catch_exceptions=(KeyError, TypeError)
)
async def some_protected_func():
# some process
The sync and async implementations follow the same interface, so you only need to change the import path:
lasier.circuit_breaker.sync
: for sync implementataionlasier.circuit_breaker.asyncio
: for async implementataion
Arguments
Argument | Definition |
---|---|
rule | Instance of class rule. |
cache | Instance of the circuit breaker state storage. |
failure_exception | Exception to be raised when it exceeds the maximum number of errors and when the circuit is open. |
failure_timeout | This value is set on first error. It is used to validate the number of errors by time. (seconds, default 60) |
circuit_timeout | Time that the circuit will be open. (seconds, default 60) |
catch_exceptions | List of exceptions catched to increase the number of errors. |
WARNING: The args
failure_timeout
andcircuit_timeout
will be used on state storage commands so if you'll use libs that expects milliseconds instead of seconds ontimeout
arguments maybe you'll get yourself in trouble
Circuit state storage
Lasier works with a storage to register the current state of the circuit, number of failures, etc. That storage respects the follow interface:
from lasier.types import Timeout # Timeout = Optional[Union[int, float]]
class Storage:
def add(self, key: str, value: int, timeout: Timeout = None) -> None:
pass
def set(self, key: str, value: int, timeout: Timeout = None) -> None:
pass
def incr(self, key: str) -> int:
pass
def get(self, key: str) -> int:
pass
def expire(key: str, timeout: Timeout = None) -> None:
pass
def delete(self, key: str) -> None:
pass
def flushdb(self) -> None:
pass
For
async
circuit breaker, lasier works with that same interface however with async syntax, f.ex:async def set(self, key=str, value=int, timeout=Optional[int])
So you can use any cache/storage that respects that interface.
Adapters
If you'll use Lasier with redis-py as cache, you can use lasier.adapters.caches.redis.RedisAdapter
from lasier.adapters.caches import RedisAdapter
from redis import Redis
cache = RedisAdapter(Redis(host='localhost', port=6479, db=0))
Implemented Adapters
Lib | Adapter |
---|---|
redis-py | lasier.adapters.caches.RedisAdapter |
django-cache | lasier.adapters.caches.DjangoAdapter |
django-cache-async | lasier.adapters.caches.DjangoAsyncAdapter |
aiocache | lasier.adapters.caches.AiocacheAdapter |
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
Built Distribution
File details
Details for the file lasier-0.3.0.tar.gz
.
File metadata
- Download URL: lasier-0.3.0.tar.gz
- Upload date:
- Size: 9.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.1.14 CPython/3.7.13 Linux/5.15.0-1014-azure
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 03d5a8058adc1ff1f0d17f9e544b946bd8c6d7256dfe120288022677fc2db8ce |
|
MD5 | a9e3e1be3bfb30f21b14c10428c5c5ef |
|
BLAKE2b-256 | 8c5d9672792e0712fbbc5a3d24f9d3128e9ee53ab5a79ba204c14bc352bba679 |
File details
Details for the file lasier-0.3.0-py3-none-any.whl
.
File metadata
- Download URL: lasier-0.3.0-py3-none-any.whl
- Upload date:
- Size: 11.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.1.14 CPython/3.7.13 Linux/5.15.0-1014-azure
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 68a8218aead4a9b1ad33aaed9085575dcc128076432a0d6837cfbf214ff958f9 |
|
MD5 | 5ba960f46f477d1c3477a7ca9850eb6c |
|
BLAKE2b-256 | 97991437761145080028c5a2363b23326e3140e16f10226c53fccae0269e1f42 |