1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
use crate::error::JobError;
use std::{any::Any, error::Error, time::Duration};

/// Represents a non-error result for a [Job] or [JobFn] service.
///
/// Any job should return this as a result to control a jobs outcome.
#[derive(Debug, Clone)]
pub enum JobResult {
    /// Job successfully completed
    Success,
    /// Job needs to be manually retried.
    Retry,
    /// Job was complete as a result of being killed
    Kill,
    /// Return job back and process it in [Duration]
    Reschedule(Duration),
}

impl std::fmt::Display for JobResult {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let text = match self {
            JobResult::Success => "Success",
            JobResult::Retry => "Retry",
            JobResult::Kill => "Kill",
            JobResult::Reschedule(_) => "Reschedule",
        };
        f.write_str(text)
    }
}

/// Helper for Job Responses
pub trait IntoJobResponse {
    /// converts self into a Result
    fn into_response(self) -> Result<JobResult, JobError>;
}

impl IntoJobResponse for bool {
    fn into_response(self) -> Result<JobResult, JobError> {
        match self {
            true => Ok(JobResult::Success),
            false => Err(JobError::Unknown),
        }
    }
}

impl<T: Any, E: 'static + Error + Send + Sync> IntoJobResponse for Result<T, E> {
    fn into_response(self) -> Result<JobResult, JobError> {
        match self {
            Ok(value) => {
                let value_any = &value as &dyn Any;
                match value_any.downcast_ref::<JobResult>() {
                    Some(res) => Ok(res.clone()),
                    None => Ok(JobResult::Success),
                }
            }
            Err(e) => Err(JobError::Failed(Box::new(e))),
        }
    }
}

macro_rules! SIMPLE_JOB_RESULT {
    ($type:ty) => {
        impl IntoJobResponse for $type {
            fn into_response(self) -> Result<JobResult, JobError> {
                Ok(JobResult::Success)
            }
        }
    };
}

SIMPLE_JOB_RESULT!(());
SIMPLE_JOB_RESULT!(u8);
SIMPLE_JOB_RESULT!(u16);
SIMPLE_JOB_RESULT!(u32);
SIMPLE_JOB_RESULT!(u64);
SIMPLE_JOB_RESULT!(usize);
SIMPLE_JOB_RESULT!(i8);
SIMPLE_JOB_RESULT!(i16);
SIMPLE_JOB_RESULT!(i32);
SIMPLE_JOB_RESULT!(i64);
SIMPLE_JOB_RESULT!(isize);
SIMPLE_JOB_RESULT!(f32);
SIMPLE_JOB_RESULT!(f64);
SIMPLE_JOB_RESULT!(String);