Package: lasier
LasierA sync/async circuit breaker implementationAccording to Nygard on your masterpiece bookRelease 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.RequirementsPython >= 3.7InstalationUsingpip:pip install lasierUsageTo use lasier circuit breaker you'll need aruleand acache(the circuit state storage) instanceRuleARuleis the mechanism that define where circuit will open or close.MaxFailuresRuleRule to open circuit based on maximum number of failuresfromlasier.circuit_breaker.rulesimportMaxFailuresRulerule=MaxFailuresRule(max_failures=500,failure_cache_key='my_cb')ArgumentsArgumentDefinitionmax_failuresMaximum number of errorsfailure_cache_keyCache key where the number of errors is incrementedPercentageFailuresRuleRule to open circuit based on a percentage of failuresfromlasier.circuit_breaker.rulesimportPercentageFailuresRulerule=PercentageFailuresRule(max_failures_percentage=60,failure_cache_key='my_cb',min_accepted_requests=100,request_cache_key='my_cb_request')ArgumentsArgumentDefinitionmax_failures_percentageMaximum percentage of errorsfailure_cache_keyCache key where the number of errors is incrementedmin_accepted_requestsMinimum number of requests accepted to not open circuit breakerrequest_cache_keyCache key where the number of requests is incrementedCircuit BreakerYou can use the Lasier circuit breaker with acontext_managerf.ex:fromlasier.circuit_breaker.syncimportCircuitBreaker...defsome_protected_func():withCircuitBreaker(rule=rule,cache=cache,failure_exception=ValueError,catch_exceptions=(KeyError,TypeError)):# some processOr adecorator, f.ex:fromlasier.circuit_breaker.asyncioimportcircuit_breaker...@circuit_breaker(rule=rule,cache=cache,failure_exception=ValueError,catch_exceptions=(KeyError,TypeError))asyncdefsome_protected_func():# some processThesyncandasyncimplementations 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 implementataionArgumentsArgumentDefinitionruleInstance of classrule.cacheInstance of the circuit breakerstate storage.failure_exceptionException to be raised when it exceeds the maximum number of errors and when the circuit is open.failure_timeoutThis value is set on first error. It is used to validate the number of errors by time. (seconds, default 60)circuit_timeoutTime that the circuit will be open. (seconds, default 60)catch_exceptionsList of exceptions catched to increase the number of errors.WARNING: The argsfailure_timeoutandcircuit_timeoutwill be used on state storage commands so if you'll use libs that expects milliseconds instead of seconds ontimeoutarguments maybe you'll get yourself in troubleCircuit state storageLasier works with a storage to register the current state of the circuit, number of failures, etc. That storage respects the follow interface:fromlasier.typesimportTimeout# Timeout = Optional[Union[int, float]]classStorage:defadd(self,key:str,value:int,timeout:Timeout=None)->None:passdefset(self,key:str,value:int,timeout:Timeout=None)->None:passdefincr(self,key:str)->int:passdefget(self,key:str)->int:passdefexpire(key:str,timeout:Timeout=None)->None:passdefdelete(self,key:str)->None:passdefflushdb(self)->None:passForasynccircuit 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.AdaptersIf you'll use Lasier withredis-pyas cache, you can uselasier.adapters.caches.redis.RedisAdapterfromlasier.adapters.cachesimportRedisAdapterfromredisimportRediscache=RedisAdapter(Redis(host='localhost',port=6479,db=0))Implemented AdaptersLibAdapterredis-pylasier.adapters.caches.RedisAdapterdjango-cachelasier.adapters.caches.DjangoAdapterdjango-cache-asynclasier.adapters.caches.DjangoAsyncAdapteraiocachelasier.adapters.caches.AiocacheAdapter