[−][src]Crate recloser
recloser
A concurrent circuit breaker implemented with ring buffers.
The Recloser
struct provides a call(...)
method to wrap function calls that may fail,
it will eagerly reject them when some failure_rate
is reached, and it will allow them
again after some time.
A future aware version of call(...)
is also available through an AsyncRecloser
wrapper.
The API is largely based on failsafe and the ring buffer implementation on resilient4j.
Usage
The Recloser
can be in three states:
Closed(RingBuffer(len))
: The initialRecloser
's state. At leastlen
calls will be performed before calculating afailure_rate
based on which transitions toOpen(_)
state may happen.Open(duration)
: All calls will returnErr(Error::Rejected)
untilduration
has elapsed, then transition toHalfOpen(_)
state will happen.HalfOpen(RingBuffer(len))
: At leastlen
calls will be performed before calculating afailure_rate
based on which transitions to eitherClosed(_)
orOpen(_)
states will happen.
The state transition settings can be customized as follows:
use std::time::Duration; use recloser::Recloser; // Equivalent to Recloser::default() let recloser = Recloser::custom() .error_rate(0.5) .closed_len(100) .half_open_len(10) .open_wait(Duration::from_secs(30)) .build();
Wrapping dangerous function calls in order to control failure propagation:
use recloser::{Recloser, Error}; // Performs 1 call before calculating failure_rate let recloser = Recloser::custom().closed_len(1).build(); let f1 = || Err::<(), usize>(1); // First call, just recorded as an error let res = recloser.call(f1); assert!(matches!(res, Err(Error::Inner(1)))); // Now also computes failure_rate, that is 100% here // Will transition to State::Open afterward let res = recloser.call(f1); assert!(matches!(res, Err(Error::Inner(1)))); let f2 = || Err::<(), i64>(-1); // All calls are rejected (while in State::Open) let res = recloser.call(f2); assert!(matches!(res, Err(Error::Rejected)));
It is also possible to discard some errors on a per call basis.
This behavior is controlled by the ErrorPredicate<E>
trait, which is already
implemented for all Fn(&E) -> bool
.
use recloser::{Recloser, Error}; let recloser = Recloser::default(); let f = || Err::<(), usize>(1); // Custom predicate that doesn't consider usize values as errors let p = |_: &usize| false; // Will not record resulting Err(1) as an error let res = recloser.call_with(p, f); assert!(matches!(res, Err(Error::Inner(1))));
Wrapping functions that return Future
s requires to use an AsyncRecloser
that just
wraps a regular Recloser
.
use futures::future; use recloser::{Recloser, Error, AsyncRecloser}; let recloser = AsyncRecloser::from(Recloser::default()); let future = future::lazy(|_| Err::<(), usize>(1)); let future = recloser.call(future);
Structs
AnyError | Considers any value as a failure. |
AsyncRecloser | Provides future aware method on top of a regular |
Recloser | A concurrent cirbuit breaker based on |
RecloserBuilder | A helper struct to build customized |
RecloserFuture | Custom |
Enums
Error | Error returned by |
Traits
ErrorPredicate | A trait used to determine whether an |