mod exponential_backoff;
mod forward;
mod log_and_ignore;
use std::convert::Infallible;
use std::error::Error;
use either::Either;
use non_non_full::NonEmptyVec;
use crate::cancellation_token::CancellationToken;
use crate::error::FetcherError;
use crate::maybe_send::{MaybeSend, MaybeSendSync, MaybeSync};
pub use self::exponential_backoff::ExponentialBackoff;
pub use self::forward::Forward;
pub use self::log_and_ignore::LogAndIgnore;
pub trait HandleError<Tr>: MaybeSendSync
where
Tr: MaybeSync,
{
type HandlerErr: Error;
fn handle_errors(
&mut self,
errors: NonEmptyVec<FetcherError>,
cx: HandleErrorContext<'_, Tr>,
) -> impl Future<Output = HandleErrorResult<Self::HandlerErr>> + MaybeSend;
}
pub struct HandleErrorContext<'a, Tr>
where
Tr: MaybeSync,
{
pub job_name: &'a str,
pub job_trigger: &'a Tr,
pub cancel_token: Option<&'a mut CancellationToken>,
}
pub enum HandleErrorResult<E> {
ResumeJob {
wait_for_trigger: bool,
},
StopWithErrors(NonEmptyVec<FetcherError>),
ErrWhileHandling {
err: E,
original_errors: NonEmptyVec<FetcherError>,
},
}
impl<E> HandleErrorResult<E> {
pub fn map_handler_err<U, F>(self, f: F) -> HandleErrorResult<U>
where
F: FnOnce(E) -> U,
{
match self {
HandleErrorResult::ResumeJob {
wait_for_trigger: wait_on_the_trigger,
} => HandleErrorResult::ResumeJob {
wait_for_trigger: wait_on_the_trigger,
},
HandleErrorResult::StopWithErrors(e) => HandleErrorResult::StopWithErrors(e),
HandleErrorResult::ErrWhileHandling {
err,
original_errors,
} => HandleErrorResult::ErrWhileHandling {
err: f(err),
original_errors,
},
}
}
}
impl<A, B, Tr> HandleError<Tr> for Either<A, B>
where
A: HandleError<Tr>,
B: HandleError<Tr>,
Tr: MaybeSync,
{
type HandlerErr = Either<A::HandlerErr, B::HandlerErr>;
async fn handle_errors(
&mut self,
errors: NonEmptyVec<FetcherError>,
cx: HandleErrorContext<'_, Tr>,
) -> HandleErrorResult<Self::HandlerErr> {
match self {
Either::Left(a) => a
.handle_errors(errors, cx)
.await
.map_handler_err(Either::Left),
Either::Right(b) => b
.handle_errors(errors, cx)
.await
.map_handler_err(Either::Right),
}
}
}
impl<Tr> HandleError<Tr> for ()
where
Tr: MaybeSync,
{
type HandlerErr = <Forward as HandleError<Tr>>::HandlerErr;
async fn handle_errors(
&mut self,
errors: NonEmptyVec<FetcherError>,
cx: HandleErrorContext<'_, Tr>,
) -> HandleErrorResult<Self::HandlerErr> {
Forward.handle_errors(errors, cx).await
}
}
impl<Tr> HandleError<Tr> for Infallible
where
Tr: MaybeSync,
{
type HandlerErr = Infallible;
async fn handle_errors(
&mut self,
_errors: NonEmptyVec<FetcherError>,
_cx: HandleErrorContext<'_, Tr>,
) -> HandleErrorResult<Self::HandlerErr> {
match *self {}
}
}
#[cfg(feature = "nightly")]
impl<Tr> HandleError<Tr> for !
where
Tr: MaybeSync,
{
type HandlerErr = !;
async fn handle_errors(
&mut self,
_errors: NonEmptyVec<FetcherError>,
_cx: HandleErrorContext<'_, Tr>,
) -> HandleErrorResult<Self::HandlerErr> {
match *self {}
}
}
impl<H, Tr> HandleError<Tr> for Option<H>
where
H: HandleError<Tr>,
Tr: MaybeSync,
{
type HandlerErr = H::HandlerErr;
async fn handle_errors(
&mut self,
errors: NonEmptyVec<FetcherError>,
cx: HandleErrorContext<'_, Tr>,
) -> HandleErrorResult<Self::HandlerErr> {
let Some(inner) = self else {
match Forward.handle_errors(errors, cx).await {
HandleErrorResult::ResumeJob {
wait_for_trigger: wait_on_the_trigger,
} => {
return HandleErrorResult::ResumeJob {
wait_for_trigger: wait_on_the_trigger,
};
}
HandleErrorResult::StopWithErrors(e) => {
return HandleErrorResult::StopWithErrors(e);
}
HandleErrorResult::ErrWhileHandling { err, .. } => match err {},
}
};
inner.handle_errors(errors, cx).await
}
}
impl<H, Tr> HandleError<Tr> for &mut H
where
H: HandleError<Tr>,
Tr: MaybeSync,
{
type HandlerErr = H::HandlerErr;
fn handle_errors(
&mut self,
errors: NonEmptyVec<FetcherError>,
cx: HandleErrorContext<'_, Tr>,
) -> impl Future<Output = HandleErrorResult<Self::HandlerErr>> + MaybeSend {
(*self).handle_errors(errors, cx)
}
}