Skip to content

Commit

Permalink
chore: switch failure crate with thiserror (#1122)
Browse files Browse the repository at this point in the history
* switch fail crate to thiserror

Co-authored-by: JR Conlin <[email protected]>
  • Loading branch information
tiftran and jrconlin authored Jul 30, 2021
1 parent 503d1aa commit 5369f1a
Show file tree
Hide file tree
Showing 7 changed files with 187 additions and 133 deletions.
36 changes: 19 additions & 17 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ actix-web-httpauth = "0.5"
actix-rt = "1" # Pin to 1.0, due to dependencies on Tokio
actix-cors = "0.5"
async-trait = "0.1.40"
backtrace = "0.3.61"
base64 = "0.13"
bb8 = "0.4.1" # pin to 0.4 due to dependencies on Tokio
bytes = "1.0"
Expand All @@ -36,7 +37,6 @@ diesel_logger = "0.1.1"
diesel_migrations = { version = "1.4.0", features = ["mysql"] }
docopt = "1.1.0"
env_logger = "0.8"
failure = "0.1.8"
futures = { version = "0.3", features = ["compat"] }
googleapis-raw = { version = "0", path = "vendor/mozilla-rust-sdk/googleapis-raw" }
# Some versions of OpenSSL 1.1.1 conflict with grpcio's built-in boringssl which can cause
Expand All @@ -58,7 +58,8 @@ protobuf = "2.20.0"
rand = "0.8"
regex = "1.4"
# pin to 0.19: https://github.com/getsentry/sentry-rust/issues/277
sentry = { version = "0.19", features = ["with_curl_transport"] } # pin to 0.19 due to curl transport, failure
sentry = { version = "0.19", features = ["with_curl_transport"] }# pin to 0.19 due to curl transport, failure
sentry-backtrace = "0.19"
serde = "1.0"
serde_derive = "1.0"
serde_json = { version = "1.0", features = ["arbitrary_precision"] }
Expand All @@ -71,6 +72,7 @@ slog-mozlog-json = "0.1"
slog-scope = "4.3"
slog-stdlog = "4.1"
slog-term = "2.6"
thiserror = "1.0.26"
time = "^0.2.25"
# pinning to 0.2.4 due to high number of dependencies (actix, bb8, deadpool, etc.)
tokio = { version = "0.2.4", features = ["macros", "sync"] }
Expand Down
65 changes: 31 additions & 34 deletions src/db/error.rs
Original file line number Diff line number Diff line change
@@ -1,92 +1,89 @@
use std::fmt;

use actix_web::http::StatusCode;
use failure::{Backtrace, Context, Fail};
use thiserror::Error;

#[derive(Debug)]
#[derive(Error, Debug)]
pub struct DbError {
inner: Context<DbErrorKind>,
kind: DbErrorKind,
pub status: StatusCode,
}

#[derive(Debug, Fail)]
#[derive(Debug, Error)]
pub enum DbErrorKind {
#[fail(display = "A database error occurred: {}", _0)]
DieselQuery(#[cause] diesel::result::Error),
#[error("A database error occurred: {}", _0)]
DieselQuery(#[from] diesel::result::Error),

#[fail(
display = "An error occurred while establishing a db connection: {}",
_0
)]
DieselConnection(#[cause] diesel::result::ConnectionError),
#[error("An error occurred while establishing a db connection: {}", _0)]
DieselConnection(#[from] diesel::result::ConnectionError),

#[fail(display = "A database error occurred: {}", _0)]
SpannerGrpc(#[cause] grpcio::Error),
#[error("A database error occurred: {}", _0)]
SpannerGrpc(#[from] grpcio::Error),

#[fail(display = "Spanner data load too large: {}", _0)]
#[error("Spanner data load too large: {}", _0)]
SpannerTooLarge(String),

#[fail(display = "A database pool error occurred: {}", _0)]
#[error("A database pool error occurred: {}", _0)]
Pool(diesel::r2d2::PoolError),

#[fail(display = "Error migrating the database: {}", _0)]
#[error("Error migrating the database: {}", _0)]
Migration(diesel_migrations::RunMigrationsError),

#[fail(display = "Specified collection does not exist")]
#[error("Specified collection does not exist")]
CollectionNotFound,

#[fail(display = "Specified bso does not exist")]
#[error("Specified bso does not exist")]
BsoNotFound,

#[fail(display = "Specified batch does not exist")]
#[error("Specified batch does not exist")]
BatchNotFound,

#[fail(display = "Tokenserver user not found")]
#[error("Tokenserver user not found")]
TokenserverUserNotFound,

#[fail(display = "An attempt at a conflicting write")]
#[error("An attempt at a conflicting write")]
Conflict,

#[fail(display = "Database integrity error: {}", _0)]
#[error("Database integrity error: {}", _0)]
Integrity(String),

#[fail(display = "Invalid SYNC_DATABASE_URL: {}", _0)]
#[error("Invalid SYNC_DATABASE_URL: {}", _0)]
InvalidUrl(String),

#[fail(display = "Unexpected error: {}", _0)]
#[error("Unexpected error: {}", _0)]
Internal(String),

#[fail(display = "User over quota")]
#[error("User over quota")]
Quota,

#[fail(display = "Connection expired")]
#[error("Connection expired")]
Expired,
}

impl DbError {
pub fn kind(&self) -> &DbErrorKind {
self.inner.get_context()
&self.kind
}

pub fn internal(msg: &str) -> Self {
DbErrorKind::Internal(msg.to_owned()).into()
}

pub fn is_reportable(&self) -> bool {
!matches!(self.inner.get_context(), DbErrorKind::Conflict)
!matches!(&self.kind, DbErrorKind::Conflict)
}

pub fn metric_label(&self) -> Option<String> {
match self.inner.get_context() {
match &self.kind {
DbErrorKind::Conflict => Some("storage.conflict".to_owned()),
_ => None,
}
}
}

impl From<Context<DbErrorKind>> for DbError {
fn from(inner: Context<DbErrorKind>) -> Self {
let status = match inner.get_context() {
impl From<DbErrorKind> for DbError {
fn from(kind: DbErrorKind) -> Self {
let status = match kind {
DbErrorKind::TokenserverUserNotFound
| DbErrorKind::CollectionNotFound
| DbErrorKind::BsoNotFound => StatusCode::NOT_FOUND,
Expand All @@ -102,11 +99,11 @@ impl From<Context<DbErrorKind>> for DbError {
_ => StatusCode::INTERNAL_SERVER_ERROR,
};

Self { inner, status }
Self { kind, status }
}
}

failure_boilerplate!(DbError, DbErrorKind);
impl_fmt_display!(DbError, DbErrorKind);

from_error!(diesel::result::Error, DbError, DbErrorKind::DieselQuery);
from_error!(
Expand Down
4 changes: 2 additions & 2 deletions src/db/spanner/pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,10 +192,10 @@ impl Default for CollectionCache {
#[derive(Debug, Clone, Copy)]
pub struct LoggingErrorSink;

impl<E: failure::Fail> ErrorSink<E> for LoggingErrorSink {
impl<E: std::error::Error> ErrorSink<E> for LoggingErrorSink {
fn sink(&self, e: E) {
error!("bb8 Error: {}", e);
let event = sentry::integrations::failure::event_from_fail(&e);
let event = sentry::event_from_error(&e);
sentry::capture_event(event);
}

Expand Down
Loading

0 comments on commit 5369f1a

Please sign in to comment.