Remove anyhow

This commit is contained in:
asonix 2024-02-04 23:35:47 -06:00
parent 8217012237
commit 141db9afc8
30 changed files with 196 additions and 135 deletions

View file

@ -15,7 +15,6 @@ might not be the best experience.
[dependencies] [dependencies]
actix-rt = "2.2.0" actix-rt = "2.2.0"
background-jobs = "0.15.0" background-jobs = "0.15.0"
anyhow = "1.0"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
``` ```
@ -24,8 +23,7 @@ Jobs are a combination of the data required to perform an operation, and the log
operation. They implement the `Job`, `serde::Serialize`, and `serde::DeserializeOwned`. operation. They implement the `Job`, `serde::Serialize`, and `serde::DeserializeOwned`.
```rust ```rust
use background_jobs::Job; use background_jobs::{Job, BoxError};
use anyhow::Error;
use std::future::{ready, Ready}; use std::future::{ready, Ready};
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
@ -45,7 +43,8 @@ impl MyJob {
impl Job for MyJob { impl Job for MyJob {
type State = (); type State = ();
type Future = Ready<Result<(), Error>>; type Error = BoxError;
type Future = Ready<Result<(), BoxError>>;
const NAME: &'static str = "MyJob"; const NAME: &'static str = "MyJob";
@ -80,7 +79,8 @@ impl MyState {
impl Job for MyJob { impl Job for MyJob {
type State = MyState; type State = MyState;
type Future = Ready<Result<(), Error>>; type Error = BoxError;
type Future = Ready<Result<(), BoxError>>;
// The name of the job. It is super important that each job has a unique name, // The name of the job. It is super important that each job has a unique name,
// because otherwise one job will overwrite another job when they're being // because otherwise one job will overwrite another job when they're being
@ -126,11 +126,10 @@ With that out of the way, back to the examples:
##### Main ##### Main
```rust ```rust
use background_jobs::{create_server, WorkerConfig}; use background_jobs::{create_server, actix::WorkerConfig, BoxError};
use anyhow::Error;
#[actix_rt::main] #[actix_rt::main]
async fn main() -> Result<(), Error> { async fn main() -> Result<(), BoxError> {
// Set up our Storage // Set up our Storage
// For this example, we use the default in-memory storage mechanism // For this example, we use the default in-memory storage mechanism
use background_jobs::memory_storage::{ActixTimer, Storage}; use background_jobs::memory_storage::{ActixTimer, Storage};

View file

@ -8,7 +8,6 @@ edition = "2021"
[dependencies] [dependencies]
actix-rt = "2.0.0" actix-rt = "2.0.0"
anyhow = "1.0"
background-jobs = { version = "0.17.0", path = "../..", features = [ "error-logging", "sled" ] } background-jobs = { version = "0.17.0", path = "../..", features = [ "error-logging", "sled" ] }
tracing = "0.1" tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] } tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] }

View file

@ -1,9 +1,8 @@
use actix_rt::Arbiter; use actix_rt::Arbiter;
use anyhow::Error;
use background_jobs::{ use background_jobs::{
actix::{Spawner, WorkerConfig}, actix::{Spawner, WorkerConfig},
memory_storage::{ActixTimer, Storage}, memory_storage::{ActixTimer, Storage},
MaxRetries, UnsendJob as Job, BoxError, MaxRetries, UnsendJob as Job,
}; };
use std::{ use std::{
future::{ready, Ready}, future::{ready, Ready},
@ -26,7 +25,7 @@ pub struct MyJob {
} }
#[actix_rt::main] #[actix_rt::main]
async fn main() -> Result<(), Error> { async fn main() -> Result<(), BoxError> {
let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")); let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
tracing_subscriber::fmt::fmt() tracing_subscriber::fmt::fmt()
@ -84,8 +83,8 @@ impl MyJob {
impl Job for MyJob { impl Job for MyJob {
type State = MyState; type State = MyState;
type Error = Error; type Error = BoxError;
type Future = Ready<Result<(), Error>>; type Future = Ready<Result<(), BoxError>>;
type Spawner = Spawner; type Spawner = Spawner;
// The name of the job. It is super important that each job has a unique name, // The name of the job. It is super important that each job has a unique name,

View file

@ -8,7 +8,6 @@ edition = "2021"
[dependencies] [dependencies]
actix-rt = "2.0.0" actix-rt = "2.0.0"
anyhow = "1.0"
background-jobs = { version = "0.17.0", path = "../..", features = [ background-jobs = { version = "0.17.0", path = "../..", features = [
"error-logging", "error-logging",
"sled", "sled",

View file

@ -1,6 +1,5 @@
use actix_rt::Arbiter; use actix_rt::Arbiter;
use anyhow::Error; use background_jobs::{actix::WorkerConfig, sled::Storage, BoxError, Job, MaxRetries};
use background_jobs::{actix::WorkerConfig, sled::Storage, Job, MaxRetries};
use std::{ use std::{
future::{ready, Ready}, future::{ready, Ready},
time::{Duration, SystemTime}, time::{Duration, SystemTime},
@ -25,7 +24,7 @@ pub struct MyJob {
pub struct ErroringJob; pub struct ErroringJob;
#[actix_rt::main] #[actix_rt::main]
async fn main() -> Result<(), Error> { async fn main() -> Result<(), BoxError> {
let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")); let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
tracing_subscriber::fmt::fmt() tracing_subscriber::fmt::fmt()
@ -87,8 +86,8 @@ impl MyJob {
impl Job for MyJob { impl Job for MyJob {
type State = MyState; type State = MyState;
type Error = Error; type Error = BoxError;
type Future = Ready<Result<(), Error>>; type Future = Ready<Result<(), BoxError>>;
// The name of the job. It is super important that each job has a unique name, // The name of the job. It is super important that each job has a unique name,
// because otherwise one job will overwrite another job when they're being // because otherwise one job will overwrite another job when they're being
@ -115,10 +114,19 @@ impl Job for MyJob {
} }
} }
#[derive(Debug)]
pub struct Boom;
impl std::fmt::Display for Boom {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "boom")
}
}
impl std::error::Error for Boom {}
impl Job for ErroringJob { impl Job for ErroringJob {
type State = MyState; type State = MyState;
type Error = Error; type Error = Boom;
type Future = Ready<Result<(), Error>>; type Future = Ready<Result<(), Boom>>;
const NAME: &'static str = "ErroringJob"; const NAME: &'static str = "ErroringJob";
@ -127,6 +135,6 @@ impl Job for ErroringJob {
const MAX_RETRIES: MaxRetries = MaxRetries::Count(0); const MAX_RETRIES: MaxRetries = MaxRetries::Count(0);
fn run(self, _: MyState) -> Self::Future { fn run(self, _: MyState) -> Self::Future {
ready(Err(anyhow::anyhow!("boom"))) ready(Err(Boom))
} }
} }

View file

@ -8,7 +8,6 @@ edition = "2021"
[dependencies] [dependencies]
actix-rt = "2.0.0" actix-rt = "2.0.0"
anyhow = "1.0"
background-jobs = { version = "0.17.0", path = "../..", features = [ "error-logging", "sled" ] } background-jobs = { version = "0.17.0", path = "../..", features = [ "error-logging", "sled" ] }
tracing = "0.1" tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] } tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] }

View file

@ -1,9 +1,8 @@
use actix_rt::Arbiter; use actix_rt::Arbiter;
use anyhow::Error;
use background_jobs::{ use background_jobs::{
actix::{Spawner, WorkerConfig}, actix::{Spawner, WorkerConfig},
sled::Storage, sled::Storage,
MaxRetries, UnsendJob as Job, BoxError, MaxRetries, UnsendJob as Job,
}; };
use std::{ use std::{
future::{ready, Future, Ready}, future::{ready, Future, Ready},
@ -30,7 +29,7 @@ pub struct MyJob {
pub struct LongJob; pub struct LongJob;
#[actix_rt::main] #[actix_rt::main]
async fn main() -> Result<(), Error> { async fn main() -> Result<(), BoxError> {
let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")); let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
tracing_subscriber::fmt::fmt() tracing_subscriber::fmt::fmt()
@ -90,8 +89,8 @@ impl MyJob {
impl Job for MyJob { impl Job for MyJob {
type State = MyState; type State = MyState;
type Error = Error; type Error = BoxError;
type Future = Ready<Result<(), Error>>; type Future = Ready<Result<(), BoxError>>;
type Spawner = Spawner; type Spawner = Spawner;
// The name of the job. It is super important that each job has a unique name, // The name of the job. It is super important that each job has a unique name,
@ -121,8 +120,8 @@ impl Job for MyJob {
impl Job for LongJob { impl Job for LongJob {
type State = MyState; type State = MyState;
type Error = Error; type Error = BoxError;
type Future = Pin<Box<dyn Future<Output = Result<(), Error>>>>; type Future = Pin<Box<dyn Future<Output = Result<(), BoxError>>>>;
type Spawner = Spawner; type Spawner = Spawner;
const NAME: &'static str = "LongJob"; const NAME: &'static str = "LongJob";

View file

@ -8,7 +8,6 @@ edition = "2021"
[dependencies] [dependencies]
actix-rt = "2.0.0" actix-rt = "2.0.0"
anyhow = "1.0"
background-jobs = { version = "0.17.0", path = "../..", features = [ "error-logging", "sled"] } background-jobs = { version = "0.17.0", path = "../..", features = [ "error-logging", "sled"] }
tracing = "0.1" tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] } tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] }

View file

@ -1,9 +1,8 @@
use actix_rt::Arbiter; use actix_rt::Arbiter;
use anyhow::Error;
use background_jobs::{ use background_jobs::{
actix::{Spawner, WorkerConfig}, actix::{Spawner, WorkerConfig},
sled::Storage, sled::Storage,
MaxRetries, UnsendJob as Job, BoxError, MaxRetries, UnsendJob as Job,
}; };
use std::{ use std::{
future::{ready, Ready}, future::{ready, Ready},
@ -29,7 +28,7 @@ pub struct MyJob {
pub struct StopJob; pub struct StopJob;
#[actix_rt::main] #[actix_rt::main]
async fn main() -> Result<(), Error> { async fn main() -> Result<(), BoxError> {
let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")); let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
tracing_subscriber::fmt::fmt() tracing_subscriber::fmt::fmt()
@ -102,8 +101,8 @@ impl MyJob {
impl Job for MyJob { impl Job for MyJob {
type State = MyState; type State = MyState;
type Error = Error; type Error = BoxError;
type Future = Ready<Result<(), Error>>; type Future = Ready<Result<(), BoxError>>;
type Spawner = Spawner; type Spawner = Spawner;
// The name of the job. It is super important that each job has a unique name, // The name of the job. It is super important that each job has a unique name,
@ -133,8 +132,8 @@ impl Job for MyJob {
impl Job for StopJob { impl Job for StopJob {
type State = MyState; type State = MyState;
type Error = Error; type Error = BoxError;
type Future = Ready<Result<(), Error>>; type Future = Ready<Result<(), BoxError>>;
type Spawner = Spawner; type Spawner = Spawner;
const NAME: &'static str = "StopJob"; const NAME: &'static str = "StopJob";

View file

@ -8,7 +8,6 @@ edition = "2021"
[dependencies] [dependencies]
actix-rt = "2.0.0" actix-rt = "2.0.0"
anyhow = "1.0"
background-jobs = { version = "0.17.0", path = "../..", features = [ "error-logging", "sled" ] } background-jobs = { version = "0.17.0", path = "../..", features = [ "error-logging", "sled" ] }
tracing = "0.1" tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] } tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] }

View file

@ -1,10 +1,9 @@
use actix_rt::Arbiter; use actix_rt::Arbiter;
use anyhow::Error;
use background_jobs::{ use background_jobs::{
actix::{Spawner, WorkerConfig}, actix::{Spawner, WorkerConfig},
metrics::MetricsStorage, metrics::MetricsStorage,
sled::Storage, sled::Storage,
MaxRetries, UnsendJob as Job, BoxError, MaxRetries, UnsendJob as Job,
}; };
use std::{future::Future, pin::Pin, time::Duration}; use std::{future::Future, pin::Pin, time::Duration};
use tracing::info; use tracing::info;
@ -24,7 +23,7 @@ pub struct MyJob {
} }
#[actix_rt::main] #[actix_rt::main]
async fn main() -> Result<(), Error> { async fn main() -> Result<(), BoxError> {
let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("warn")); let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("warn"));
// Install the metrics subscriber // Install the metrics subscriber
@ -89,8 +88,8 @@ impl MyJob {
impl Job for MyJob { impl Job for MyJob {
type State = MyState; type State = MyState;
type Error = Error; type Error = BoxError;
type Future = Pin<Box<dyn Future<Output = Result<(), Error>> + 'static>>; type Future = Pin<Box<dyn Future<Output = Result<(), BoxError>> + 'static>>;
type Spawner = Spawner; type Spawner = Spawner;
// The name of the job. It is super important that each job has a unique name, // The name of the job. It is super important that each job has a unique name,

View file

@ -7,7 +7,6 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
anyhow = "1.0"
background-jobs = { version = "0.17.0", path = "../..", default-features = false, features = [ "error-logging", "sled", "tokio" ] } background-jobs = { version = "0.17.0", path = "../..", default-features = false, features = [ "error-logging", "sled", "tokio" ] }
time = "0.3" time = "0.3"
tokio = { version = "1", features = ["full"] } tokio = { version = "1", features = ["full"] }

View file

@ -1,5 +1,4 @@
use anyhow::Error; use background_jobs::{sled::Storage, tokio::WorkerConfig, BoxError, Job, MaxRetries};
use background_jobs::{sled::Storage, tokio::WorkerConfig, Job, MaxRetries};
use std::{ use std::{
future::{ready, Ready}, future::{ready, Ready},
time::{Duration, SystemTime}, time::{Duration, SystemTime},
@ -24,7 +23,7 @@ pub struct MyJob {
pub struct PanickingJob; pub struct PanickingJob;
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), Error> { async fn main() -> Result<(), BoxError> {
let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")); let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
tracing_subscriber::fmt::fmt() tracing_subscriber::fmt::fmt()
@ -83,8 +82,8 @@ impl MyJob {
impl Job for MyJob { impl Job for MyJob {
type State = MyState; type State = MyState;
type Error = Error; type Error = BoxError;
type Future = Ready<Result<(), Error>>; type Future = Ready<Result<(), BoxError>>;
// The name of the job. It is super important that each job has a unique name, // The name of the job. It is super important that each job has a unique name,
// because otherwise one job will overwrite another job when they're being // because otherwise one job will overwrite another job when they're being
@ -113,8 +112,8 @@ impl Job for MyJob {
impl Job for PanickingJob { impl Job for PanickingJob {
type State = MyState; type State = MyState;
type Error = Error; type Error = BoxError;
type Future = Ready<Result<(), Error>>; type Future = Ready<Result<(), BoxError>>;
const NAME: &'static str = "PanickingJob"; const NAME: &'static str = "PanickingJob";

View file

@ -7,7 +7,6 @@ edition = "2021"
[dependencies] [dependencies]
actix-rt = "2.9.0" actix-rt = "2.9.0"
anyhow = "1.0.79"
background-jobs = { version = "0.17.0", features = ["postgres"], path = "../.." } background-jobs = { version = "0.17.0", features = ["postgres"], path = "../.." }
serde = { version = "1.0.195", features = ["derive"] } serde = { version = "1.0.195", features = ["derive"] }
tokio = { version = "1.35.1", features = ["full"] } tokio = { version = "1.35.1", features = ["full"] }

View file

@ -2,7 +2,7 @@ use actix_rt::Arbiter;
use background_jobs::{ use background_jobs::{
actix::{Spawner, WorkerConfig}, actix::{Spawner, WorkerConfig},
postgres::Storage, postgres::Storage,
MaxRetries, UnsendJob as Job, BoxError, MaxRetries, UnsendJob as Job,
}; };
// use background_jobs_sled_storage::Storage; // use background_jobs_sled_storage::Storage;
use std::{ use std::{
@ -26,7 +26,7 @@ pub struct MyJob {
} }
#[actix_rt::main] #[actix_rt::main]
async fn main() -> anyhow::Result<()> { async fn main() -> Result<(), BoxError> {
let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")); let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
tracing_subscriber::fmt::fmt() tracing_subscriber::fmt::fmt()
@ -90,8 +90,8 @@ impl MyJob {
impl Job for MyJob { impl Job for MyJob {
type State = MyState; type State = MyState;
type Error = anyhow::Error; type Error = BoxError;
type Future = Ready<anyhow::Result<()>>; type Future = Ready<Result<(), BoxError>>;
type Spawner = Spawner; type Spawner = Spawner;
// The name of the job. It is super important that each job has a unique name, // The name of the job. It is super important that each job has a unique name,

View file

@ -7,7 +7,6 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
anyhow = "1.0"
background-jobs = { version = "0.17.0", path = "../..", default-features = false, features = [ "error-logging", "sled", "tokio"] } background-jobs = { version = "0.17.0", path = "../..", default-features = false, features = [ "error-logging", "sled", "tokio"] }
tokio = { version = "1", features = ["full"] } tokio = { version = "1", features = ["full"] }
tracing = "0.1" tracing = "0.1"

View file

@ -1,8 +1,7 @@
use anyhow::Error;
use background_jobs::{ use background_jobs::{
memory_storage::{Storage, TokioTimer}, memory_storage::{Storage, TokioTimer},
tokio::WorkerConfig, tokio::WorkerConfig,
Job, MaxRetries, BoxError, Job, MaxRetries,
}; };
use std::{ use std::{
future::{ready, Ready}, future::{ready, Ready},
@ -25,7 +24,7 @@ pub struct MyJob {
} }
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), Error> { async fn main() -> Result<(), BoxError> {
let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")); let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
tracing_subscriber::fmt::fmt() tracing_subscriber::fmt::fmt()
@ -79,8 +78,8 @@ impl MyJob {
impl Job for MyJob { impl Job for MyJob {
type State = MyState; type State = MyState;
type Error = Error; type Error = BoxError;
type Future = Ready<Result<(), Error>>; type Future = Ready<Result<(), BoxError>>;
// The name of the job. It is super important that each job has a unique name, // The name of the job. It is super important that each job has a unique name,
// because otherwise one job will overwrite another job when they're being // because otherwise one job will overwrite another job when they're being

View file

@ -11,7 +11,6 @@ edition = "2021"
[dependencies] [dependencies]
actix-rt = "2.5.1" actix-rt = "2.5.1"
anyhow = "1.0"
async-trait = "0.1.24" async-trait = "0.1.24"
background-jobs-core = { version = "0.17.0", path = "../jobs-core" } background-jobs-core = { version = "0.17.0", path = "../jobs-core" }
metrics = "0.22.0" metrics = "0.22.0"

View file

@ -12,8 +12,7 @@
//! //!
//! ### Example //! ### Example
//! ```rust //! ```rust
//! use anyhow::Error; //! use background_jobs_core::{Backoff, Job, MaxRetries, BoxError};
//! use background_jobs_core::{Backoff, Job, MaxRetries};
//! use background_jobs_actix::{ActixTimer, WorkerConfig}; //! use background_jobs_actix::{ActixTimer, WorkerConfig};
//! use std::future::{ready, Ready}; //! use std::future::{ready, Ready};
//! //!
@ -31,7 +30,7 @@
//! } //! }
//! //!
//! #[actix_rt::main] //! #[actix_rt::main]
//! async fn main() -> Result<(), Error> { //! async fn main() -> Result<(), BoxError> {
//! // Set up our Storage //! // Set up our Storage
//! // For this example, we use the default in-memory storage mechanism //! // For this example, we use the default in-memory storage mechanism
//! use background_jobs_core::memory_storage::Storage; //! use background_jobs_core::memory_storage::Storage;
@ -72,7 +71,7 @@
//! //!
//! impl Job for MyJob { //! impl Job for MyJob {
//! type State = MyState; //! type State = MyState;
//! type Future = Ready<Result<(), Error>>; //! type Future = Ready<Result<(), BoxError>>;
//! //!
//! // The name of the job. It is super important that each job has a unique name, //! // The name of the job. It is super important that each job has a unique name,
//! // because otherwise one job will overwrite another job when they're being //! // because otherwise one job will overwrite another job when they're being
@ -114,9 +113,8 @@
//! ``` //! ```
use actix_rt::{Arbiter, ArbiterHandle}; use actix_rt::{Arbiter, ArbiterHandle};
use anyhow::Error;
use background_jobs_core::{ use background_jobs_core::{
memory_storage::Timer, new_job, new_scheduled_job, Job, ProcessorMap, Storage, memory_storage::Timer, new_job, new_scheduled_job, BoxError, Job, ProcessorMap, Storage,
}; };
use std::{ use std::{
collections::BTreeMap, collections::BTreeMap,
@ -469,7 +467,7 @@ impl QueueHandle {
/// ///
/// This job will be sent to the server for storage, and will execute whenever a worker for the /// This job will be sent to the server for storage, and will execute whenever a worker for the
/// job's queue is free to do so. /// job's queue is free to do so.
pub async fn queue<J>(&self, job: J) -> Result<(), Error> pub async fn queue<J>(&self, job: J) -> Result<(), BoxError>
where where
J: Job, J: Job,
{ {
@ -482,7 +480,7 @@ impl QueueHandle {
/// ///
/// This job will be sent to the server for storage, and will execute after the specified time /// This job will be sent to the server for storage, and will execute after the specified time
/// and when a worker for the job's queue is free to do so. /// and when a worker for the job's queue is free to do so.
pub async fn schedule<J>(&self, job: J, after: SystemTime) -> Result<(), Error> pub async fn schedule<J>(&self, job: J, after: SystemTime) -> Result<(), BoxError>
where where
J: Job, J: Job,
{ {

View file

@ -1,16 +1,15 @@
use anyhow::Error; use background_jobs_core::{BoxError, JobInfo, NewJobInfo, ReturnJobInfo, Storage};
use background_jobs_core::{JobInfo, NewJobInfo, ReturnJobInfo, Storage};
use uuid::Uuid; use uuid::Uuid;
#[async_trait::async_trait] #[async_trait::async_trait]
pub(crate) trait ActixStorage { pub(crate) trait ActixStorage {
async fn push(&self, job: NewJobInfo) -> Result<Uuid, Error>; async fn push(&self, job: NewJobInfo) -> Result<Uuid, BoxError>;
async fn pop(&self, queue: &str, runner_id: Uuid) -> Result<JobInfo, Error>; async fn pop(&self, queue: &str, runner_id: Uuid) -> Result<JobInfo, BoxError>;
async fn heartbeat(&self, job_id: Uuid, runner_id: Uuid) -> Result<(), Error>; async fn heartbeat(&self, job_id: Uuid, runner_id: Uuid) -> Result<(), BoxError>;
async fn complete(&self, ret: ReturnJobInfo) -> Result<(), Error>; async fn complete(&self, ret: ReturnJobInfo) -> Result<(), BoxError>;
} }
pub(crate) struct StorageWrapper<S>(pub(crate) S) pub(crate) struct StorageWrapper<S>(pub(crate) S)
@ -24,19 +23,19 @@ where
S: Storage + Send + Sync, S: Storage + Send + Sync,
S::Error: Send + Sync + 'static, S::Error: Send + Sync + 'static,
{ {
async fn push(&self, job: NewJobInfo) -> Result<Uuid, Error> { async fn push(&self, job: NewJobInfo) -> Result<Uuid, BoxError> {
Ok(self.0.push(job).await?) Ok(self.0.push(job).await?)
} }
async fn pop(&self, queue: &str, runner_id: Uuid) -> Result<JobInfo, Error> { async fn pop(&self, queue: &str, runner_id: Uuid) -> Result<JobInfo, BoxError> {
Ok(self.0.pop(queue, runner_id).await?) Ok(self.0.pop(queue, runner_id).await?)
} }
async fn heartbeat(&self, job_id: Uuid, runner_id: Uuid) -> Result<(), Error> { async fn heartbeat(&self, job_id: Uuid, runner_id: Uuid) -> Result<(), BoxError> {
Ok(self.0.heartbeat(job_id, runner_id).await?) Ok(self.0.heartbeat(job_id, runner_id).await?)
} }
async fn complete(&self, ret: ReturnJobInfo) -> Result<(), Error> { async fn complete(&self, ret: ReturnJobInfo) -> Result<(), BoxError> {
self.0.complete(ret).await?; self.0.complete(ret).await?;
Ok(()) Ok(())

View file

@ -18,7 +18,6 @@ completion-logging = []
error-logging = [] error-logging = []
[dependencies] [dependencies]
anyhow = "1.0"
async-trait = "0.1.24" async-trait = "0.1.24"
event-listener = "4" event-listener = "4"
metrics = "0.22.0" metrics = "0.22.0"

View file

@ -0,0 +1,71 @@
/// A simple error box that provides no additional formatting utilities
pub struct BoxError {
error: Box<dyn std::error::Error + Send + Sync>,
}
impl std::fmt::Debug for BoxError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.error.fmt(f)
}
}
impl std::fmt::Display for BoxError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.error.fmt(f)
}
}
impl<E> From<E> for BoxError
where
E: std::error::Error + Send + Sync + 'static,
{
fn from(error: E) -> Self {
BoxError {
error: Box::new(error),
}
}
}
impl From<BoxError> for Box<dyn std::error::Error + Send + Sync> {
fn from(value: BoxError) -> Self {
value.error
}
}
impl From<BoxError> for Box<dyn std::error::Error + Send> {
fn from(value: BoxError) -> Self {
value.error
}
}
impl From<BoxError> for Box<dyn std::error::Error> {
fn from(value: BoxError) -> Self {
value.error
}
}
impl AsRef<dyn std::error::Error + Send + Sync> for BoxError {
fn as_ref(&self) -> &(dyn std::error::Error + Send + Sync + 'static) {
self.error.as_ref()
}
}
impl AsRef<dyn std::error::Error + Send> for BoxError {
fn as_ref(&self) -> &(dyn std::error::Error + Send + 'static) {
self.error.as_ref()
}
}
impl AsRef<dyn std::error::Error> for BoxError {
fn as_ref(&self) -> &(dyn std::error::Error + 'static) {
self.error.as_ref()
}
}
impl std::ops::Deref for BoxError {
type Target = dyn std::error::Error + Send + Sync;
fn deref(&self) -> &Self::Target {
self.error.as_ref()
}
}

View file

@ -1,5 +1,4 @@
use crate::{Backoff, JobError, MaxRetries, NewJobInfo}; use crate::{Backoff, BoxError, JobError, MaxRetries, NewJobInfo};
use anyhow::Error;
use serde::{de::DeserializeOwned, ser::Serialize}; use serde::{de::DeserializeOwned, ser::Serialize};
use serde_json::Value; use serde_json::Value;
use std::{future::Future, pin::Pin, time::SystemTime}; use std::{future::Future, pin::Pin, time::SystemTime};
@ -15,8 +14,7 @@ use tracing::{Instrument, Span};
/// ### Example /// ### Example
/// ///
/// ```rust /// ```rust
/// use anyhow::Error; /// use background_jobs_core::{Job, new_job, BoxError};
/// use background_jobs_core::{Job, new_job};
/// use tracing::info; /// use tracing::info;
/// use std::future::{ready, Ready}; /// use std::future::{ready, Ready};
/// ///
@ -27,7 +25,8 @@ use tracing::{Instrument, Span};
/// ///
/// impl Job for MyJob { /// impl Job for MyJob {
/// type State = (); /// type State = ();
/// type Future = Ready<Result<(), Error>>; /// type Error = BoxError;
/// type Future = Ready<Result<(), BoxError>>;
/// ///
/// const NAME: &'static str = "MyJob"; /// const NAME: &'static str = "MyJob";
/// ///
@ -38,7 +37,7 @@ use tracing::{Instrument, Span};
/// } /// }
/// } /// }
/// ///
/// fn main() -> Result<(), Error> { /// fn main() -> Result<(), BoxError> {
/// let job = new_job(MyJob { count: 1234 })?; /// let job = new_job(MyJob { count: 1234 })?;
/// ///
/// Ok(()) /// Ok(())
@ -49,7 +48,7 @@ pub trait Job: Serialize + DeserializeOwned + 'static {
type State: Clone + 'static; type State: Clone + 'static;
/// The error type this job returns /// The error type this job returns
type Error: Into<Box<dyn std::error::Error>>; type Error: Into<BoxError>;
/// The future returned by this job /// The future returned by this job
type Future: Future<Output = Result<(), Self::Error>> + Send; type Future: Future<Output = Result<(), Self::Error>> + Send;
@ -130,7 +129,7 @@ pub trait Job: Serialize + DeserializeOwned + 'static {
} }
/// A provided method to create a new JobInfo from provided arguments /// A provided method to create a new JobInfo from provided arguments
pub fn new_job<J>(job: J) -> Result<NewJobInfo, Error> pub fn new_job<J>(job: J) -> Result<NewJobInfo, BoxError>
where where
J: Job, J: Job,
{ {
@ -147,7 +146,7 @@ where
} }
/// Create a NewJobInfo to schedule a job to be performed after a certain time /// Create a NewJobInfo to schedule a job to be performed after a certain time
pub fn new_scheduled_job<J>(job: J, after: SystemTime) -> Result<NewJobInfo, Error> pub fn new_scheduled_job<J>(job: J, after: SystemTime) -> Result<NewJobInfo, BoxError>
where where
J: Job, J: Job,
{ {
@ -178,13 +177,13 @@ where
Box::pin(async move { Box::pin(async move {
let (fut, span) = res?; let (fut, span) = res?;
if let Some(span) = span { let res = if let Some(span) = span {
fut.instrument(span).await.map_err(Into::into)?; fut.instrument(span).await
} else { } else {
fut.await.map_err(Into::into)?; fut.await
} };
Ok(()) res.map_err(Into::into).map_err(JobError::Processing)
}) })
} }

View file

@ -6,6 +6,7 @@
//! This crate shouldn't be depended on directly, except in the case of implementing a custom jobs //! This crate shouldn't be depended on directly, except in the case of implementing a custom jobs
//! processor. For a default solution based on Actix and Sled, look at the `background-jobs` crate. //! processor. For a default solution based on Actix and Sled, look at the `background-jobs` crate.
mod box_error;
mod catch_unwind; mod catch_unwind;
mod job; mod job;
mod job_info; mod job_info;
@ -14,6 +15,7 @@ mod storage;
mod unsend_job; mod unsend_job;
pub use crate::{ pub use crate::{
box_error::BoxError,
job::{new_job, new_scheduled_job, process, Job}, job::{new_job, new_scheduled_job, process, Job},
job_info::{JobInfo, NewJobInfo, ReturnJobInfo}, job_info::{JobInfo, NewJobInfo, ReturnJobInfo},
processor_map::{CachedProcessorMap, ProcessorMap}, processor_map::{CachedProcessorMap, ProcessorMap},
@ -27,7 +29,7 @@ pub use unsend_job::{JoinError, UnsendJob, UnsendSpawner};
pub enum JobError { pub enum JobError {
/// Some error occurred while processing the job /// Some error occurred while processing the job
#[error("{0}")] #[error("{0}")]
Processing(#[from] Box<dyn std::error::Error>), Processing(#[from] BoxError),
/// Creating a `Job` type from the provided `serde_json::Value` failed /// Creating a `Job` type from the provided `serde_json::Value` failed
#[error("Could not make JSON value from arguments")] #[error("Could not make JSON value from arguments")]

View file

@ -188,10 +188,11 @@ where
ReturnJobInfo::pass(id) ReturnJobInfo::pass(id)
} }
Ok(Err(e)) => { Ok(Err(e)) => {
let display = format!("{}", e); let display = format!("{e}");
let debug = format!("{:?}", e);
span.record("exception.message", &tracing::field::display(&display)); span.record("exception.message", &tracing::field::display(&display));
let debug = format!("{e:?}");
span.record("exception.details", &tracing::field::display(&debug)); span.record("exception.details", &tracing::field::display(&debug));
#[cfg(feature = "error-logging")] #[cfg(feature = "error-logging")]
tracing::warn!("Job {queue}: {name}-{id} errored"); tracing::warn!("Job {queue}: {name}-{id} errored");
ReturnJobInfo::fail(id) ReturnJobInfo::fail(id)

View file

@ -1,4 +1,4 @@
use crate::{Backoff, Job, MaxRetries}; use crate::{Backoff, BoxError, Job, MaxRetries};
use serde::{de::DeserializeOwned, ser::Serialize}; use serde::{de::DeserializeOwned, ser::Serialize};
use std::{ use std::{
fmt::Debug, fmt::Debug,
@ -45,7 +45,7 @@ pub trait UnsendJob: Serialize + DeserializeOwned + 'static {
type State: Clone + 'static; type State: Clone + 'static;
/// The error type this job returns /// The error type this job returns
type Error: Into<Box<dyn std::error::Error>> + Send; type Error: Into<BoxError>;
/// The future returned by this job /// The future returned by this job
/// ///
@ -150,7 +150,7 @@ where
T: UnsendJob, T: UnsendJob,
{ {
type State = T::State; type State = T::State;
type Error = T::Error; type Error = BoxError;
type Future = UnwrapFuture<<T::Spawner as UnsendSpawner>::Handle<Result<(), Self::Error>>>; type Future = UnwrapFuture<<T::Spawner as UnsendSpawner>::Handle<Result<(), Self::Error>>>;
const NAME: &'static str = <Self as UnsendJob>::NAME; const NAME: &'static str = <Self as UnsendJob>::NAME;
@ -161,7 +161,8 @@ where
fn run(self, state: Self::State) -> Self::Future { fn run(self, state: Self::State) -> Self::Future {
UnwrapFuture(T::Spawner::spawn( UnwrapFuture(T::Spawner::spawn(
UnsendJob::run(self, state).instrument(Span::current()), async move { UnsendJob::run(self, state).await.map_err(Into::into) }
.instrument(Span::current()),
)) ))
} }

View file

@ -12,7 +12,6 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
anyhow = "1.0.79"
async-trait = "0.1.77" async-trait = "0.1.77"
background-jobs-core = { version = "0.17.0", path = "../jobs-core" } background-jobs-core = { version = "0.17.0", path = "../jobs-core" }
metrics = "0.22.0" metrics = "0.22.0"

View file

@ -12,8 +12,7 @@
//! //!
//! ### Example //! ### Example
//! ```rust //! ```rust
//! use anyhow::Error; //! use background_jobs_core::{Backoff, Job, MaxRetries, BoxError};
//! use background_jobs_core::{Backoff, Job, MaxRetries};
//! use background_jobs_tokio::{TokioTimer, WorkerConfig}; //! use background_jobs_tokio::{TokioTimer, WorkerConfig};
//! use std::future::{ready, Ready}; //! use std::future::{ready, Ready};
//! //!
@ -31,7 +30,7 @@
//! } //! }
//! //!
//! #[tokio::main] //! #[tokio::main]
//! async fn main() -> Result<(), Error> { //! async fn main() -> Result<(), BoxError> {
//! // Set up our Storage //! // Set up our Storage
//! // For this example, we use the default in-memory storage mechanism //! // For this example, we use the default in-memory storage mechanism
//! use background_jobs_core::memory_storage::Storage; //! use background_jobs_core::memory_storage::Storage;
@ -74,7 +73,7 @@
//! //!
//! impl Job for MyJob { //! impl Job for MyJob {
//! type State = MyState; //! type State = MyState;
//! type Future = Ready<Result<(), Error>>; //! type Future = Ready<Result<(), BoxError>>;
//! //!
//! // The name of the job. It is super important that each job has a unique name, //! // The name of the job. It is super important that each job has a unique name,
//! // because otherwise one job will overwrite another job when they're being //! // because otherwise one job will overwrite another job when they're being
@ -115,9 +114,9 @@
//! } //! }
//! ``` //! ```
use anyhow::Error;
use background_jobs_core::{ use background_jobs_core::{
memory_storage::Timer, new_job, new_scheduled_job, Job, ProcessorMap, Storage as StorageTrait, memory_storage::Timer, new_job, new_scheduled_job, BoxError, Job, ProcessorMap,
Storage as StorageTrait,
}; };
use std::{ use std::{
collections::{BTreeMap, HashMap}, collections::{BTreeMap, HashMap},
@ -314,7 +313,7 @@ impl QueueHandle {
/// ///
/// This job will be sent to the server for storage, and will execute whenever a worker for the /// This job will be sent to the server for storage, and will execute whenever a worker for the
/// job's queue is free to do so. /// job's queue is free to do so.
pub async fn queue<J>(&self, job: J) -> Result<(), Error> pub async fn queue<J>(&self, job: J) -> Result<(), BoxError>
where where
J: Job, J: Job,
{ {
@ -327,7 +326,7 @@ impl QueueHandle {
/// ///
/// This job will be sent to the server for storage, and will execute after the specified time /// This job will be sent to the server for storage, and will execute after the specified time
/// and when a worker for the job's queue is free to do so. /// and when a worker for the job's queue is free to do so.
pub async fn schedule<J>(&self, job: J, after: SystemTime) -> Result<(), Error> pub async fn schedule<J>(&self, job: J, after: SystemTime) -> Result<(), BoxError>
where where
J: Job, J: Job,
{ {

View file

@ -1,17 +1,17 @@
use std::{ops::Deref, sync::Arc}; use std::{ops::Deref, sync::Arc};
use background_jobs_core::{JobInfo, NewJobInfo, ReturnJobInfo, Storage as StorageTrait}; use background_jobs_core::{BoxError, JobInfo, NewJobInfo, ReturnJobInfo, Storage as StorageTrait};
use uuid::Uuid; use uuid::Uuid;
#[async_trait::async_trait] #[async_trait::async_trait]
pub trait TokioStorage: Send + Sync { pub trait TokioStorage: Send + Sync {
async fn push(&self, job: NewJobInfo) -> anyhow::Result<Uuid>; async fn push(&self, job: NewJobInfo) -> Result<Uuid, BoxError>;
async fn pop(&self, queue: &str, runner_id: Uuid) -> anyhow::Result<JobInfo>; async fn pop(&self, queue: &str, runner_id: Uuid) -> Result<JobInfo, BoxError>;
async fn heartbeat(&self, job_id: Uuid, worker_id: Uuid) -> anyhow::Result<()>; async fn heartbeat(&self, job_id: Uuid, worker_id: Uuid) -> Result<(), BoxError>;
async fn complete(&self, return_job_info: ReturnJobInfo) -> anyhow::Result<()>; async fn complete(&self, return_job_info: ReturnJobInfo) -> Result<(), BoxError>;
} }
#[derive(Clone)] #[derive(Clone)]
@ -26,19 +26,22 @@ impl<S> TokioStorage for StorageWrapper<S>
where where
S: StorageTrait + Send + Sync + 'static, S: StorageTrait + Send + Sync + 'static,
{ {
async fn push(&self, job: NewJobInfo) -> anyhow::Result<Uuid> { async fn push(&self, job: NewJobInfo) -> Result<Uuid, BoxError> {
self.0.push(job).await.map_err(From::from) self.0.push(job).await.map_err(From::from)
} }
async fn pop(&self, queue: &str, runner_id: Uuid) -> anyhow::Result<JobInfo> { async fn pop(&self, queue: &str, runner_id: Uuid) -> Result<JobInfo, BoxError> {
self.0.pop(queue, runner_id).await.map_err(From::from) self.0.pop(queue, runner_id).await.map_err(From::from)
} }
async fn heartbeat(&self, job_id: Uuid, runner_id: Uuid) -> anyhow::Result<()> { async fn heartbeat(&self, job_id: Uuid, runner_id: Uuid) -> Result<(), BoxError> {
self.0.heartbeat(job_id, runner_id).await.map_err(From::from) self.0
.heartbeat(job_id, runner_id)
.await
.map_err(From::from)
} }
async fn complete(&self, return_job_info: ReturnJobInfo) -> anyhow::Result<()> { async fn complete(&self, return_job_info: ReturnJobInfo) -> Result<(), BoxError> {
self.0 self.0
.complete(return_job_info) .complete(return_job_info)
.await .await

View file

@ -29,7 +29,6 @@
//! ```toml //! ```toml
//! [dependencies] //! [dependencies]
//! actix-rt = "2.6.0" //! actix-rt = "2.6.0"
//! anyhow = "1.0"
//! background-jobs = "0.15.0" //! background-jobs = "0.15.0"
//! serde = { version = "1.0", features = ["derive"] } //! serde = { version = "1.0", features = ["derive"] }
//! ``` //! ```
@ -39,8 +38,7 @@
//! operation. They implment the `Job`, `serde::Serialize`, and `serde::DeserializeOwned`. //! operation. They implment the `Job`, `serde::Serialize`, and `serde::DeserializeOwned`.
//! //!
//! ```rust,ignore //! ```rust,ignore
//! use anyhow::Error; //! use background_jobs::[Job, BoxError};
//! use background_jobs::Job;
//! use std::future::{ready, Ready}; //! use std::future::{ready, Ready};
//! //!
//! #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] //! #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
@ -60,7 +58,8 @@
//! //!
//! impl Job for MyJob { //! impl Job for MyJob {
//! type State = (); //! type State = ();
//! type Future = Ready<Result<(), Error>>; //! type Error = BoxError;
//! type Future = Ready<Result<(), BoxError>>;
//! //!
//! const NAME: &'static str = "MyJob"; //! const NAME: &'static str = "MyJob";
//! //!
@ -80,8 +79,7 @@
//! Let's re-define the job to care about some application state. //! Let's re-define the job to care about some application state.
//! //!
//! ```rust,ignore //! ```rust,ignore
//! use anyhow::Error; //! use background_jobs::[Job, BoxError};
//! use background_jobs::Job;
//! use std::future::{ready, Ready}; //! use std::future::{ready, Ready};
//! //!
//! #[derive(Clone, Debug)] //! #[derive(Clone, Debug)]
@ -99,7 +97,8 @@
//! //!
//! impl Job for MyJob { //! impl Job for MyJob {
//! type State = MyState; //! type State = MyState;
//! type Future = Ready<Result<(), Error>>; //! type Error = BoxError;
//! type Future = Ready<Result<(), BoxError>>;
//! //!
//! const NAME: &'static str = "MyJob"; //! const NAME: &'static str = "MyJob";
//! //!
@ -123,11 +122,10 @@
//! //!
//! ##### Main //! ##### Main
//! ```rust,ignore //! ```rust,ignore
//! use anyhow::Error; //! use background_jobs::{ServerConfig, memory_storage::Storage, actix::WorkerConfig, BoxError};
//! use background_jobs::{ServerConfig, memory_storage::Storage, WorkerConfig};
//! //!
//! #[actix_rt::main] //! #[actix_rt::main]
//! async fn main() -> Result<(), Error> { //! async fn main() -> Result<(), BoxError> {
//! // Set up our Storage //! // Set up our Storage
//! let storage = Storage::new(); //! let storage = Storage::new();
//! //!
@ -173,7 +171,7 @@
//! | `completion-logging` | Enables a tracing event that occurs whenever a job completes | //! | `completion-logging` | Enables a tracing event that occurs whenever a job completes |
//! | `error-logging` | Enables a tracing event that occurs whenever a job fails | //! | `error-logging` | Enables a tracing event that occurs whenever a job fails |
pub use background_jobs_core::{Backoff, Job, MaxRetries, UnsendJob, UnsendSpawner}; pub use background_jobs_core::{Backoff, BoxError, Job, MaxRetries, UnsendJob, UnsendSpawner};
#[cfg(feature = "metrics")] #[cfg(feature = "metrics")]
pub mod metrics { pub mod metrics {