Failure handling in Rust
I’ve been working on WeeRust recently which is an IRC client developed using the Rust programming language. A problem recently prevented WeeRust from forwarding the message to me over IMAP because of a temporary network hiccup. Reviewing the code I found an oversight where the send_email()
method returns an Option<u32>
when instead it should return a Result<(), AppErr>
because send_email()
can fail. I would like to handle that failure gracefully instead of panic which is what happened the other night crashing my client and disconnecting me from the IRC network. I added the question mark operator to the send_email
method here (more details about the question mark here . The question mark operator combined with the signature change will now match either Ok(t)
or Err(e)
, and if the match is an Err
, then the function will immediately return Err(e.into())
(more on how into() works later). From here there’s a few options; we can create a retry strategy, hold the message in a buffer until it can be viewed later, inform the sender the message can’t be delivered or some combination. Since this application is very much a WIP I decided to just inform the sender the message can’t be forwarded for the time being.
The other change this required is adding a new option to the enum
SmtpError(lettre::transport::smtp::Error)
Next, we need to add a new trait From<T> to the enum. This new From trait does a value-to-value conversion. In our case, it converts:
SmtpError(lettre::transport::smtp::Error)
To:
AppErr::SmtpError(error)
Here is the trait definition looks:
impl From<lettre::transport::smtp::Error> for AppErr {
fn from(error: lettre::transport::smtp::Error) -> Self {
AppErr::SmtpError(error)
}
}
The newly introduced question mark operator can return something that is AppErr::..
even though the original error was a different type. Wrapping an error in a common type while still maintaining the original context information which can be useful for debugging. This is a common pattern for designing error propagation in Rust as described here . The full commit is here .