Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make error handling more robust #3

Open
eureka-cpu opened this issue Mar 13, 2024 · 0 comments
Open

Make error handling more robust #3

eureka-cpu opened this issue Mar 13, 2024 · 0 comments
Assignees
Labels
enhancement Improvement to an existing feature

Comments

@eureka-cpu
Copy link

eureka-cpu commented Mar 13, 2024

This crate contains an error handling anti-pattern, specifically in reference to the Handler trait's on_error method. The method is not an associated function, but does not use self and accepts an error type value. This method should be removed, and instead the Result type in theater_types should be a newtype instead of an alias, with more robust error handling methods implemented on it.

For example:

use thiserror; // 1.0.57
use tracing; // 0.1.40
use std::{error::Error, fmt::Debug};

#[derive(thiserror::Error, Debug)]
enum MyError {
    #[error("failed to do... something")]
    Broken,
}

#[derive(Debug)]
struct MyType;

/// Similar to `Result` or `Option` for returning values from a handler.
/// Useful for exiting a handler gracefully on error types that
/// would otherwise stop a program.
#[derive(Debug)]
enum Recover<T> {
    Value(T),
    State(ActorState),
}

/// This type already exists in the Theater crate
#[derive(Debug)]
enum ActorState {
    Running,
    // ...
}

/// This type will replace `theater::Result`
struct TheaterResult<T, E: Error + Debug>(Result<T, E>);
impl<T, E: Error + Debug> TheaterResult<T, E> {
    /// Logs error types with extra context, converting the error to a recoverable state,
    /// otherwise forwarding the contained value.
    ///
    /// Based on the `.inspect_err` method in `std::result::Result`, with the
    /// focus on recovering from handler execution failure.
    ///
    /// ```rust, ignore
    /// // res represents the returned type of some handler function
    /// let res: TheaterResult<MyType, MyError> = TheaterResult(Err(MyError::Broken));
    /// let err = res.with_context("broken for... reasons");
    /// println!("{err:?}");
    /// ```
    fn with_context(self, context: &str) -> Recover<T> {
        if let Err(ref err) = self.0 {
            if !context.is_empty() {
                tracing::error!("{context}: {err:?}");
            } else {
                tracing::error!("{err:?}");
            }
            Recover::State(ActorState::Running)
        } else {
            Recover::Value(self.0.unwrap())
        }
    }
    
    /// Shorthand for `.with_context()` when no extra context is needed.
    ///
    /// Logs error types, converting the error to a recoverable state,
    /// otherwise forwarding the contained value.
    ///
    /// Based on the `.inspect_err` method in `std::result::Result`, with the
    /// focus on recovering from handler execution failure.
    ///
    /// ```rust, ignore
    /// // res represents the returned type of some handler function
    /// let res: TheaterResult<MyType, MyError> = TheaterResult(Err(MyError::Broken));
    /// let err = res.on_err();
    /// println!("{err:?}");
    /// ```
    fn on_err(self) -> Recover<T> {
        self.with_context("")
    }
}

fn main() {
    // res represents the returned type of some handler function
    let res: TheaterResult<MyType, MyError> = TheaterResult(Err(MyError::Broken));
    let err = res.with_context("broken for... reasons");
    println!("{err:?}");

    let res: TheaterResult<MyType, MyError> = TheaterResult(Ok(MyType));
    let value = res.on_err();
    println!("{value:?}")
}
@eureka-cpu eureka-cpu added the enhancement Improvement to an existing feature label Mar 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Improvement to an existing feature
Projects
None yet
Development

No branches or pull requests

2 participants