1use std::error::Error;
8
9use async_trait::async_trait;
10use serde_json::Value;
11
12use crate::director::Director;
13
14#[derive(Debug)]
16pub enum JobResult {
17 Accept,
19 Defer(String),
21 Reject(String),
23 Fail(Box<dyn Error + Send + 'static>),
25 Restart,
27 Done,
29}
30
31impl JobResult {
32 pub fn accept() -> Self {
34 Self::Accept
35 }
36
37 pub fn defer<M>(msg: M) -> Self
39 where
40 M: Into<String>,
41 {
42 Self::Defer(msg.into())
43 }
44
45 pub fn reject<M>(msg: M) -> Self
47 where
48 M: Into<String>,
49 {
50 Self::Reject(msg.into())
51 }
52
53 pub fn fail<E>(err: E) -> Self
55 where
56 E: Into<Box<dyn Error + Send + Sync + 'static>>,
57 {
58 Self::Fail(err.into())
59 }
60
61 pub fn restart() -> Self {
63 Self::Restart
64 }
65
66 pub fn done() -> Self {
68 Self::Done
69 }
70
71 pub fn combine(self, other: Self) -> Self {
73 match (self, other) {
74 (Self::Accept, next) | (next, Self::Accept) => next,
76 (Self::Done, _) | (_, Self::Done) => Self::Done,
78 (Self::Restart, _) | (_, Self::Restart) => Self::Restart,
80 (Self::Defer(left), Self::Defer(right)) => Self::Defer(format!("{}\n{}", left, right)),
82 (defer @ Self::Defer(_), _) | (_, defer @ Self::Defer(_)) => defer,
83 (fail @ Self::Fail(_), _) | (_, fail @ Self::Fail(_)) => fail,
85 (Self::Reject(left), Self::Reject(right)) => {
87 Self::Reject(format!("{}\n{}", left, right))
88 },
89 }
90 }
91}
92
93pub type JobError = Box<dyn Error + Send + Sync>;
95
96pub trait HandlerCore {
98 fn add_to_director<'a>(&'a self, director: &mut Director<'a>) -> Result<(), JobError>;
100}
101
102#[async_trait]
104pub trait Handler: HandlerCore {
105 async fn handle(
107 &self,
108 kind: &str,
109 object: &Value,
110 retry_count: usize,
111 ) -> Result<JobResult, JobError>;
112}
113
114#[cfg(test)]
115mod tests {
116 use crate::JobResult;
117
118 #[test]
119 fn test_job_result_ctors() {
120 assert!(matches!(JobResult::accept(), JobResult::Accept));
121 if let JobResult::Defer(d) = JobResult::defer("hi") {
122 assert_eq!(d, "hi");
123 } else {
124 panic!("`JobResult::defer` doesn't return a `JobResult::Defer` variant");
125 }
126 if let JobResult::Reject(d) = JobResult::reject("hi") {
127 assert_eq!(d, "hi");
128 } else {
129 panic!("`JobResult::reject` doesn't return a `JobResult::Reject` variant");
130 }
131 if let JobResult::Fail(d) = JobResult::fail("hi") {
132 assert_eq!(format!("{}", d), "hi");
133 } else {
134 panic!("`JobResult::fail` doesn't return a `JobResult::Fail` variant");
135 }
136 assert!(matches!(JobResult::restart(), JobResult::Restart));
137 assert!(matches!(JobResult::done(), JobResult::Done));
138 }
139
140 #[test]
141 fn test_job_result_combine() {
142 let accept = || JobResult::accept();
143 let defer = |d| JobResult::defer(d);
144 let reject = |d| JobResult::reject(d);
145 let fail = |d| JobResult::fail(d);
146 let restart = || JobResult::restart();
147 let done = || JobResult::done();
148
149 assert!(matches!(accept().combine(accept()), JobResult::Accept));
150 if let JobResult::Defer(d) = JobResult::accept().combine(JobResult::defer("defer2")) {
151 assert_eq!(d, "defer2");
152 } else {
153 panic!("`JobResult::Accept` combined with `::Defer` should return a `::Defer`");
154 }
155 if let JobResult::Reject(d) = accept().combine(reject("reject2")) {
156 assert_eq!(d, "reject2");
157 } else {
158 panic!("`JobResult::Accept` combined with `::Reject` should return a `::Reject`");
159 }
160 if let JobResult::Fail(d) = accept().combine(fail("fail2")) {
161 assert_eq!(format!("{}", d), "fail2");
162 } else {
163 panic!("`JobResult::Accept` combined with `::Fail` should return a `::Fail`");
164 }
165 assert!(matches!(accept().combine(restart()), JobResult::Restart));
166 assert!(matches!(accept().combine(done()), JobResult::Done));
167
168 if let JobResult::Defer(d) = defer("defer1").combine(accept()) {
169 assert_eq!(d, "defer1");
170 } else {
171 panic!("`JobResult::Defer` combined with `::Accept` should return a `::Defer`");
172 }
173 if let JobResult::Defer(d) = defer("defer1").combine(defer("defer2")) {
174 assert_eq!(d, "defer1\ndefer2");
175 } else {
176 panic!("`JobResult::Defer` combined with `::Defer` should return a `::Defer`");
177 }
178 if let JobResult::Defer(d) = defer("defer1").combine(reject("reject2")) {
179 assert_eq!(d, "defer1");
180 } else {
181 panic!("`JobResult::Defer` combined with `::Reject` should return a `::Defer`");
182 }
183 if let JobResult::Defer(d) = defer("defer1").combine(fail("fail2")) {
184 assert_eq!(d, "defer1");
185 } else {
186 panic!("`JobResult::Defer` combined with `::Fail` should return a `::Defer`");
187 }
188 assert!(matches!(
189 defer("defer1").combine(restart()),
190 JobResult::Restart,
191 ));
192 assert!(matches!(defer("defer1").combine(done()), JobResult::Done));
193
194 if let JobResult::Reject(d) = reject("reject1").combine(accept()) {
195 assert_eq!(d, "reject1");
196 } else {
197 panic!("`JobResult::Reject` combined with `::Accept` should return a `::Reject`");
198 }
199 if let JobResult::Defer(d) = reject("reject1").combine(defer("defer2")) {
200 assert_eq!(d, "defer2");
201 } else {
202 panic!("`JobResult::Reject` combined with `::Defer` should return a `::Defer`");
203 }
204 if let JobResult::Reject(d) = reject("reject1").combine(reject("reject2")) {
205 assert_eq!(d, "reject1\nreject2");
206 } else {
207 panic!("`JobResult::Reject` combined with `::Reject` should return a `::Reject`");
208 }
209 if let JobResult::Fail(d) = reject("reject1").combine(fail("fail2")) {
210 assert_eq!(format!("{}", d), "fail2");
211 } else {
212 panic!("`JobResult::Reject` combined with `::Fail` should return a `::Fail`");
213 }
214 assert!(matches!(
215 reject("reject1").combine(restart()),
216 JobResult::Restart,
217 ));
218 assert!(matches!(reject("reject1").combine(done()), JobResult::Done));
219
220 if let JobResult::Fail(d) = fail("fail1").combine(accept()) {
221 assert_eq!(format!("{}", d), "fail1");
222 } else {
223 panic!("`JobResult::Fail` combined with `::Accept` should return a `::Fail`");
224 }
225 if let JobResult::Defer(d) = fail("fail1").combine(defer("defer2")) {
226 assert_eq!(format!("{}", d), "defer2");
227 } else {
228 panic!("`JobResult::Fail` combined with `::Defer` should return a `::Defer`");
229 }
230 if let JobResult::Fail(d) = fail("fail1").combine(reject("reject2")) {
231 assert_eq!(format!("{}", d), "fail1");
232 } else {
233 panic!("`JobResult::Fail` combined with `::Reject` should return a `::Fail`");
234 }
235 if let JobResult::Fail(d) = fail("fail1").combine(fail("fail2")) {
236 assert_eq!(format!("{}", d), "fail1");
237 } else {
238 panic!("`JobResult::Fail` combined with `::Fail` should return a `::Fail`");
239 }
240 assert!(matches!(
241 fail("fail1").combine(restart()),
242 JobResult::Restart,
243 ));
244 assert!(matches!(fail("fail1").combine(done()), JobResult::Done));
245
246 assert!(matches!(restart().combine(accept()), JobResult::Restart));
247 assert!(matches!(
248 restart().combine(defer("defer2")),
249 JobResult::Restart,
250 ));
251 assert!(matches!(
252 restart().combine(reject("reject2")),
253 JobResult::Restart,
254 ));
255 assert!(matches!(
256 restart().combine(fail("fail2")),
257 JobResult::Restart,
258 ));
259 assert!(matches!(restart().combine(restart()), JobResult::Restart));
260 assert!(matches!(restart().combine(done()), JobResult::Done));
261
262 assert!(matches!(done().combine(accept()), JobResult::Done));
263 assert!(matches!(done().combine(defer("defer2")), JobResult::Done));
264 assert!(matches!(done().combine(reject("reject2")), JobResult::Done));
265 assert!(matches!(done().combine(fail("fail2")), JobResult::Done));
266 assert!(matches!(done().combine(restart()), JobResult::Done));
267 assert!(matches!(done().combine(done()), JobResult::Done));
268 }
269}