Skip to main content

modo/job/
handler.rs

1use std::future::Future;
2
3use crate::error::Result;
4
5use super::context::{FromJobContext, JobContext};
6
7/// Trait implemented by all valid job handler functions.
8///
9/// A job handler is any `async fn` whose arguments each implement
10/// [`FromJobContext`]. Up to 12 arguments are supported via blanket
11/// implementations.
12///
13/// You never implement this trait directly — write a plain `async fn` and pass
14/// it to [`WorkerBuilder::register`](super::worker::WorkerBuilder::register).
15///
16/// # Supported signatures
17///
18/// ```rust,no_run
19/// use modo::job::{Payload, Meta};
20/// use serde::Deserialize;
21///
22/// #[derive(Deserialize)]
23/// struct MyPayload { value: u32 }
24///
25/// // Zero arguments
26/// async fn job_no_args() -> modo::Result<()> { Ok(()) }
27///
28/// // One argument
29/// async fn job_one_arg(payload: Payload<MyPayload>) -> modo::Result<()> { Ok(()) }
30///
31/// // Multiple arguments (up to 12)
32/// async fn job_two_args(payload: Payload<MyPayload>, meta: Meta) -> modo::Result<()> { Ok(()) }
33/// ```
34pub trait JobHandler<Args>: Clone + Send + 'static {
35    /// Invoke the handler with extracted arguments from `ctx`.
36    ///
37    /// # Errors
38    ///
39    /// Returns an error if argument extraction from the context fails or if
40    /// the handler function itself returns an error.
41    fn call(self, ctx: JobContext) -> impl Future<Output = Result<()>> + Send;
42}
43
44// 0 args
45impl<F, Fut> JobHandler<()> for F
46where
47    F: FnOnce() -> Fut + Clone + Send + 'static,
48    Fut: Future<Output = Result<()>> + Send,
49{
50    async fn call(self, _ctx: JobContext) -> Result<()> {
51        (self)().await
52    }
53}
54
55macro_rules! impl_job_handler {
56    ($($T:ident),+) => {
57        impl<F, Fut, $($T),+> JobHandler<($($T,)+)> for F
58        where
59            F: FnOnce($($T),+) -> Fut + Clone + Send + 'static,
60            Fut: Future<Output = Result<()>> + Send,
61            $($T: FromJobContext,)+
62        {
63            #[allow(non_snake_case)]
64            async fn call(self, ctx: JobContext) -> Result<()> {
65                $(let $T = $T::from_job_context(&ctx)?;)+
66                (self)($($T),+).await
67            }
68        }
69    };
70}
71
72impl_job_handler!(T1);
73impl_job_handler!(T1, T2);
74impl_job_handler!(T1, T2, T3);
75impl_job_handler!(T1, T2, T3, T4);
76impl_job_handler!(T1, T2, T3, T4, T5);
77impl_job_handler!(T1, T2, T3, T4, T5, T6);
78impl_job_handler!(T1, T2, T3, T4, T5, T6, T7);
79impl_job_handler!(T1, T2, T3, T4, T5, T6, T7, T8);
80impl_job_handler!(T1, T2, T3, T4, T5, T6, T7, T8, T9);
81impl_job_handler!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
82impl_job_handler!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
83impl_job_handler!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);