Resilient
|
Detectors are the classes used by Resilient to determine whether a function failed or not. More...
Classes | |
class | resilient::Always |
A detector which always detects failure. More... | |
class | resilient::Any< Detectors > |
Combine a group of detector, detecting a failure if any of them detect a failure. More... | |
struct | resilient::StatelessDetector< Detector > |
An helper base detector to simplify writing stateless detectors. More... | |
struct | resilient::FailureDetectorTag< FailureTypes > |
Helper struct which defines the required types for the detector concept. More... | |
class | resilient::ICallResult< T > |
Interface to represent the result of calling a detected function. More... | |
class | resilient::Never |
A detector which never detects failure. More... | |
class | resilient::Returns< T > |
A detector which detect whether a function returns a specific value. More... | |
class | resilient::Throws< T > |
A detector which detect whether a function throws an exception of a given type. More... | |
Typedefs | |
template<typename... FailureTypes> | |
using | resilient::returned_failure_t = typename detail::returned_failure< FailureTypes... >::type |
Type alias to the Variant containing either NoFailure or the failure types. More... | |
Functions | |
template<typename Failure , if_is_variant< Failure > = nullptr> | |
bool | resilient::holds_failure (Failure &&failure) |
Whether a failure contains a failure or not. More... | |
Detectors are the classes used by Resilient to determine whether a function failed or not.
There must be a way for the library for detecting when a function has failed.
Common ways are to return a specific error code, throw an exception, and many other. In order to allow you to define the failure conditions appropriate for your use case Resilient uses Detectors
.
A detector is a class which is able to determine how a function behaved, and can return a different type depending on the type of the failure.
A function which the return value will be used to detect a failure is called the detected function
.
Any class can be used as a detector as long as it implements the expected concept.
A detector must define the types:
failure_types
: a tuple of the possible Failures this detector can detect.A detector must define the methods:
State preRun()
Failure postRun(State&&, ICallResult<T>&)
Deriving from FailureDetectorTag<MyFailure1, MyFailure2, ...>
defines the failure_types
for you.
preRun()
is called before the detected function is called. The returned type State
can be any type, and it will be moved back into the postRun()
method when invoked. The State
type can be used to store some state the detector needs to keep between calls to preRun
and postRun
.
postRun()
is called after the detected function is called. The type returned by preRun()
is moved into it as first argument and an instance of ICallResult
with the type returned by the detected function is passed as a second argument. T
is the type returned by the detected function. Failure
needs to be a variant which containes either NoFailure
if no failure was detected or one of the types used in failure_types
if a failure was detected.
ICallResult
can be used to determine whether the function returned normally or threw an exception and can also return a const reference to the value returned by the function or to the threw exception.
The detector can also "consume" an exception, which means that the exception should be considered handled.
The Detector is not required to be stateless, but being stateless heavily simplify writing a detector as it prevents problems with multi-threading, it can be invoked multiple times and it can also be used in different tasks.
To make this simple the preRun()
function can return an object of any type, which will be moved back into the postRun()
function.
The detector can initialize any resource it needs inside the preRun()
method and store it into the state. The postRun()
method can then make use of the resources initialized by preRun()
and release them at the end of the method.
If the state object is the owner of the resources and RAII is used then the code has no clean-up to do.
If a Detector requires no state a NoState
type can be used as return type.
using resilient::returned_failure_t = typedef typename detail::returned_failure<FailureTypes...>::type |
Type alias to the Variant containing either NoFailure
or the failure types.
FailureTypes... | The failure types that can be returned. If it's a single tuple then the content of the tuple is used instead. |
bool resilient::holds_failure | ( | Failure && | failure | ) |
Whether a failure contains a failure or not.
Failure | The type of the Failure returned by the detector. |
nullptr | SFINAE out if it's not a Variant. |
failure | The Failure returned by the detector. |