use std::{
error::Error as StdError,
marker::PhantomData,
pin::Pin,
task::{Context, Poll},
time::Duration,
};
use thiserror::Error;
use tower_service::Service;
pub type BoxDynError = Box<dyn StdError + 'static + Send + Sync>;
#[derive(Error, Debug)]
#[error("AbortError: {source}")]
pub struct AbortError {
#[source]
source: BoxDynError,
}
impl AbortError {
pub fn new<E: Into<BoxDynError>>(err: E) -> Self {
Self { source: err.into() }
}
}
#[derive(Error, Debug)]
#[error("RetryError: {source}")]
pub struct RetryAfterError {
#[source]
source: BoxDynError,
duration: Duration,
}
impl RetryAfterError {
pub fn new<E: Into<BoxDynError>>(err: E, duration: Duration) -> Self {
Self {
source: err.into(),
duration,
}
}
#[must_use]
pub fn get_duration(&self) -> Duration {
self.duration
}
}
#[derive(Error, Debug)]
#[error("DeferredError: {source}")]
pub struct DeferredError {
#[source]
source: BoxDynError,
}
impl DeferredError {
pub fn new<E: Into<BoxDynError>>(source: E) -> Self {
Self {
source: source.into(),
}
}
}
#[non_exhaustive]
#[derive(Error, Debug)]
pub enum WorkerError {
#[error("Failed to poll backend: {0}")]
BackendError(BoxDynError),
#[error("Failed to handle the new state: {0}")]
StateError(#[from] WorkerStateError),
#[error("Worker panicked: {0}")]
PanicError(String),
#[error("IO error: {0}")]
IoError(#[from] std::io::Error),
}
#[derive(Error, Debug)]
#[non_exhaustive]
pub enum WorkerStateError {
#[error("Worker not started, did you forget to call worker.start()")]
NotStarted,
#[error("Worker already started")]
AlreadyStarted,
#[error("Worker is not running")]
NotRunning,
#[error("Worker is not paused")]
NotPaused,
#[error("Worker is shutting down")]
ShuttingDown,
#[error("Worker provided with invalid state {0}")]
InvalidState(String),
}
#[derive(Clone, Debug)]
pub struct ErrorHandlingLayer {
_p: PhantomData<()>,
}
impl ErrorHandlingLayer {
#[must_use]
pub fn new() -> Self {
Self { _p: PhantomData }
}
}
impl Default for ErrorHandlingLayer {
fn default() -> Self {
Self::new()
}
}
impl<S> tower_layer::Layer<S> for ErrorHandlingLayer {
type Service = ErrorHandlingService<S>;
fn layer(&self, service: S) -> Self::Service {
ErrorHandlingService { service }
}
}
#[derive(Clone, Debug)]
pub struct ErrorHandlingService<S> {
service: S,
}
impl<S, Request> Service<Request> for ErrorHandlingService<S>
where
S: Service<Request>,
S::Error: std::error::Error + Send + Sync + 'static,
S::Future: Send + 'static,
{
type Response = S::Response;
type Error = BoxDynError;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx).map_err(|e| {
let boxed_error: BoxDynError = e.into();
boxed_error
})
}
fn call(&mut self, req: Request) -> Self::Future {
let fut = self.service.call(req);
Box::pin(async move {
fut.await.map_err(|e| {
let boxed_error: BoxDynError = e.into();
boxed_error
})
})
}
}