[−][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 async::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 matches::assert_matches; 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 matches::assert_matches; 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}; use recloser::r#async::AsyncRecloser; let recloser = AsyncRecloser::from(Recloser::default()); let future = future::lazy(|_| Err::<(), usize>(1)); let future = recloser.call(future);
Modules
async |
Structs
AnyError | Considers any value as a failure. |
Recloser | A concurrent cirbuit breaker based on |
RecloserBuilder | A helper struct to build customized |
Enums
Error | Error returned by |
Traits
ErrorPredicate | A trait used to determine whether an |