42 lines
1.1 KiB
Rust
42 lines
1.1 KiB
Rust
use thiserror::Error;
|
|
|
|
#[derive(Error, Debug)]
|
|
pub enum StorageError {
|
|
#[error("session not found: {0}")]
|
|
NotFound(String),
|
|
|
|
#[error("session already exists: {0}")]
|
|
AlreadyExists(String),
|
|
|
|
#[error("database error: {0}")]
|
|
Database(#[from] sqlx::Error),
|
|
|
|
#[error("serialization error: {0}")]
|
|
Serialization(String),
|
|
|
|
#[error("schema migration error: {0}")]
|
|
Migration(String),
|
|
|
|
#[error("storage conflict: {0}")]
|
|
Conflict(String),
|
|
}
|
|
|
|
impl StorageError {
|
|
/// Only retry failures that can plausibly clear without changing the data.
|
|
pub fn is_transient(&self) -> bool {
|
|
let Self::Database(error) = self else {
|
|
return false;
|
|
};
|
|
match error {
|
|
sqlx::Error::PoolTimedOut => true,
|
|
sqlx::Error::Database(database) => {
|
|
matches!(database.code().as_deref(), Some("5" | "6" | "261" | "262")) || {
|
|
let message = database.message().to_ascii_lowercase();
|
|
message.contains("database is locked") || message.contains("database is busy")
|
|
}
|
|
}
|
|
_ => false,
|
|
}
|
|
}
|
|
}
|