2020-04-21 00:30:56 +00:00
|
|
|
use crate::{Backoff, Job, MaxRetries};
|
2020-03-30 15:36:49 +00:00
|
|
|
use serde::{de::DeserializeOwned, ser::Serialize};
|
2021-10-11 23:49:39 +00:00
|
|
|
use std::{
|
|
|
|
fmt::Debug,
|
|
|
|
future::Future,
|
|
|
|
pin::Pin,
|
|
|
|
task::{Context, Poll},
|
|
|
|
};
|
2024-01-08 22:37:32 +00:00
|
|
|
use tracing::{Instrument, Span};
|
2020-03-30 15:36:49 +00:00
|
|
|
|
2024-01-08 00:52:09 +00:00
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
|
|
/// The type produced when a task is dropped before completion as a result of being deliberately
|
|
|
|
/// canceled, or it panicking
|
|
|
|
pub struct JoinError;
|
|
|
|
|
|
|
|
impl std::fmt::Display for JoinError {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
write!(f, "Task has been canceled")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl std::error::Error for JoinError {}
|
|
|
|
|
|
|
|
/// The mechanism used to spawn Unsend futures, making them Send
|
|
|
|
pub trait UnsendSpawner {
|
|
|
|
/// The Handle to the job, implements a Send future with the Job's output
|
|
|
|
type Handle<T>: Future<Output = Result<T, JoinError>> + Send + Unpin
|
|
|
|
where
|
|
|
|
T: Send;
|
|
|
|
|
|
|
|
/// Spawn the unsend future producing a Send handle
|
|
|
|
fn spawn<Fut>(future: Fut) -> Self::Handle<Fut::Output>
|
|
|
|
where
|
|
|
|
Fut: Future + 'static,
|
|
|
|
Fut::Output: Send + 'static;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// The UnsendJob trait defines parameters pertaining to an instance of a background job
|
2020-03-30 15:36:49 +00:00
|
|
|
///
|
2024-01-08 00:52:09 +00:00
|
|
|
/// This trait is used to implement generic Unsend Jobs in the background jobs library. It requires
|
|
|
|
/// that implementors specify a spawning mechanism that can turn an Unsend future into a Send
|
|
|
|
/// future
|
|
|
|
pub trait UnsendJob: Serialize + DeserializeOwned + 'static {
|
2020-03-30 15:36:49 +00:00
|
|
|
/// The application state provided to this job at runtime.
|
|
|
|
type State: Clone + 'static;
|
|
|
|
|
2024-02-05 04:19:41 +00:00
|
|
|
/// The error type this job returns
|
|
|
|
type Error: Into<Box<dyn std::error::Error>> + Send;
|
|
|
|
|
2020-03-30 15:36:49 +00:00
|
|
|
/// The future returned by this job
|
2020-04-21 00:30:56 +00:00
|
|
|
///
|
|
|
|
/// Importantly, this Future does not require Send
|
2024-02-05 04:19:41 +00:00
|
|
|
type Future: Future<Output = Result<(), Self::Error>>;
|
2020-03-30 15:36:49 +00:00
|
|
|
|
2024-01-08 00:52:09 +00:00
|
|
|
/// The spawner type that will be used to spawn the unsend future
|
|
|
|
type Spawner: UnsendSpawner;
|
|
|
|
|
2020-04-21 00:30:56 +00:00
|
|
|
/// The name of the job
|
|
|
|
///
|
|
|
|
/// This name must be unique!!!
|
|
|
|
const NAME: &'static str;
|
|
|
|
|
|
|
|
/// The name of the default queue for this job
|
|
|
|
///
|
|
|
|
/// This can be overridden on an individual-job level, but if a non-existant queue is supplied,
|
|
|
|
/// the job will never be processed.
|
|
|
|
const QUEUE: &'static str = "default";
|
|
|
|
|
|
|
|
/// Define the default number of retries for this job
|
|
|
|
///
|
|
|
|
/// Defaults to Count(5)
|
|
|
|
/// Jobs can override
|
|
|
|
const MAX_RETRIES: MaxRetries = MaxRetries::Count(5);
|
|
|
|
|
|
|
|
/// Define the default backoff strategy for this job
|
|
|
|
///
|
|
|
|
/// Defaults to Exponential(2)
|
|
|
|
/// Jobs can override
|
|
|
|
const BACKOFF: Backoff = Backoff::Exponential(2);
|
|
|
|
|
2024-01-10 21:06:36 +00:00
|
|
|
/// Define how often a job should update its heartbeat timestamp
|
2020-04-21 00:30:56 +00:00
|
|
|
///
|
|
|
|
/// This is important for allowing the job server to reap processes that were started but never
|
|
|
|
/// completed.
|
|
|
|
///
|
2024-01-10 21:06:36 +00:00
|
|
|
/// Defaults to 5 seconds
|
2020-04-21 00:30:56 +00:00
|
|
|
/// Jobs can override
|
2024-01-10 21:06:36 +00:00
|
|
|
const HEARTBEAT_INTERVAL: u64 = 5_000;
|
2020-04-21 00:30:56 +00:00
|
|
|
|
2020-03-30 15:36:49 +00:00
|
|
|
/// Users of this library must define what it means to run a job.
|
|
|
|
///
|
|
|
|
/// This should contain all the logic needed to complete a job. If that means queuing more
|
|
|
|
/// jobs, sending an email, shelling out (don't shell out), or doing otherwise lengthy
|
|
|
|
/// processes, that logic should all be called from inside this method.
|
|
|
|
///
|
|
|
|
/// The state passed into this job is initialized at the start of the application. The state
|
|
|
|
/// argument could be useful for containing a hook into something like r2d2, or the address of
|
|
|
|
/// an actor in an actix-based system.
|
|
|
|
fn run(self, state: Self::State) -> Self::Future;
|
|
|
|
|
2021-09-21 15:32:48 +00:00
|
|
|
/// Generate a Span that the job will be processed within
|
|
|
|
fn span(&self) -> Option<Span> {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
2020-04-21 00:30:56 +00:00
|
|
|
/// If this job should not use it's default queue, this can be overridden in
|
2020-03-30 15:36:49 +00:00
|
|
|
/// user-code.
|
2020-04-21 00:30:56 +00:00
|
|
|
fn queue(&self) -> &str {
|
|
|
|
Self::QUEUE
|
2020-03-30 15:36:49 +00:00
|
|
|
}
|
|
|
|
|
2020-04-21 00:30:56 +00:00
|
|
|
/// If this job should not use it's default maximum retry count, this can be
|
2020-03-30 15:36:49 +00:00
|
|
|
/// overridden in user-code.
|
2020-04-21 00:30:56 +00:00
|
|
|
fn max_retries(&self) -> MaxRetries {
|
|
|
|
Self::MAX_RETRIES
|
2020-03-30 15:36:49 +00:00
|
|
|
}
|
|
|
|
|
2020-04-21 00:30:56 +00:00
|
|
|
/// If this job should not use it's default backoff strategy, this can be
|
2020-03-30 15:36:49 +00:00
|
|
|
/// overridden in user-code.
|
2020-04-21 00:30:56 +00:00
|
|
|
fn backoff_strategy(&self) -> Backoff {
|
|
|
|
Self::BACKOFF
|
2020-03-30 15:36:49 +00:00
|
|
|
}
|
|
|
|
|
2024-01-10 21:06:36 +00:00
|
|
|
/// Define how often a job should update its heartbeat timestamp
|
2020-03-30 15:36:49 +00:00
|
|
|
///
|
|
|
|
/// This is important for allowing the job server to reap processes that were started but never
|
|
|
|
/// completed.
|
2024-01-10 21:06:36 +00:00
|
|
|
fn heartbeat_interval(&self) -> u64 {
|
|
|
|
Self::HEARTBEAT_INTERVAL
|
2020-03-30 15:36:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-11 23:49:39 +00:00
|
|
|
#[doc(hidden)]
|
|
|
|
pub struct UnwrapFuture<F>(F);
|
|
|
|
|
|
|
|
impl<F, T, E> Future for UnwrapFuture<F>
|
|
|
|
where
|
|
|
|
F: Future<Output = Result<T, E>> + Unpin,
|
|
|
|
E: Debug,
|
|
|
|
{
|
|
|
|
type Output = T;
|
|
|
|
|
|
|
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
|
|
|
Pin::new(&mut self.0).poll(cx).map(|res| res.unwrap())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-30 15:36:49 +00:00
|
|
|
impl<T> Job for T
|
|
|
|
where
|
2024-01-08 00:54:14 +00:00
|
|
|
T: UnsendJob,
|
2020-03-30 15:36:49 +00:00
|
|
|
{
|
|
|
|
type State = T::State;
|
2024-02-05 04:19:41 +00:00
|
|
|
type Error = T::Error;
|
|
|
|
type Future = UnwrapFuture<<T::Spawner as UnsendSpawner>::Handle<Result<(), Self::Error>>>;
|
2020-03-30 15:36:49 +00:00
|
|
|
|
2024-01-08 00:52:09 +00:00
|
|
|
const NAME: &'static str = <Self as UnsendJob>::NAME;
|
|
|
|
const QUEUE: &'static str = <Self as UnsendJob>::QUEUE;
|
|
|
|
const MAX_RETRIES: MaxRetries = <Self as UnsendJob>::MAX_RETRIES;
|
|
|
|
const BACKOFF: Backoff = <Self as UnsendJob>::BACKOFF;
|
2024-01-10 21:06:36 +00:00
|
|
|
const HEARTBEAT_INTERVAL: u64 = <Self as UnsendJob>::HEARTBEAT_INTERVAL;
|
2020-04-21 00:30:56 +00:00
|
|
|
|
2020-03-30 15:36:49 +00:00
|
|
|
fn run(self, state: Self::State) -> Self::Future {
|
2024-01-08 00:52:09 +00:00
|
|
|
UnwrapFuture(T::Spawner::spawn(
|
|
|
|
UnsendJob::run(self, state).instrument(Span::current()),
|
|
|
|
))
|
2020-03-30 15:36:49 +00:00
|
|
|
}
|
|
|
|
|
2021-09-21 15:32:48 +00:00
|
|
|
fn span(&self) -> Option<Span> {
|
2024-01-08 00:52:09 +00:00
|
|
|
UnsendJob::span(self)
|
2021-09-21 15:32:48 +00:00
|
|
|
}
|
|
|
|
|
2020-04-21 00:30:56 +00:00
|
|
|
fn queue(&self) -> &str {
|
2024-01-08 00:52:09 +00:00
|
|
|
UnsendJob::queue(self)
|
2020-03-30 15:36:49 +00:00
|
|
|
}
|
|
|
|
|
2020-04-21 00:30:56 +00:00
|
|
|
fn max_retries(&self) -> MaxRetries {
|
2024-01-08 00:52:09 +00:00
|
|
|
UnsendJob::max_retries(self)
|
2020-03-30 15:36:49 +00:00
|
|
|
}
|
|
|
|
|
2020-04-21 00:30:56 +00:00
|
|
|
fn backoff_strategy(&self) -> Backoff {
|
2024-01-08 00:52:09 +00:00
|
|
|
UnsendJob::backoff_strategy(self)
|
2020-03-30 15:36:49 +00:00
|
|
|
}
|
|
|
|
|
2024-01-10 21:06:36 +00:00
|
|
|
fn heartbeat_interval(&self) -> u64 {
|
|
|
|
UnsendJob::heartbeat_interval(self)
|
2020-03-30 15:36:49 +00:00
|
|
|
}
|
|
|
|
}
|