Skip to main content

systemprompt_provider_contracts/
job.rs

1use anyhow::Result;
2use async_trait::async_trait;
3use std::collections::HashMap;
4use std::sync::Arc;
5
6#[derive(Debug, Clone)]
7pub struct JobResult {
8    pub success: bool,
9    pub message: Option<String>,
10    pub items_processed: Option<u64>,
11    pub items_failed: Option<u64>,
12    pub duration_ms: u64,
13}
14
15impl JobResult {
16    pub const fn success() -> Self {
17        Self {
18            success: true,
19            message: None,
20            items_processed: None,
21            items_failed: None,
22            duration_ms: 0,
23        }
24    }
25
26    pub fn with_message(mut self, message: impl Into<String>) -> Self {
27        self.message = Some(message.into());
28        self
29    }
30
31    pub const fn with_stats(mut self, processed: u64, failed: u64) -> Self {
32        self.items_processed = Some(processed);
33        self.items_failed = Some(failed);
34        self
35    }
36
37    pub const fn with_duration(mut self, duration_ms: u64) -> Self {
38        self.duration_ms = duration_ms;
39        self
40    }
41
42    pub fn failure(message: impl Into<String>) -> Self {
43        Self {
44            success: false,
45            message: Some(message.into()),
46            items_processed: None,
47            items_failed: None,
48            duration_ms: 0,
49        }
50    }
51}
52
53pub struct JobContext {
54    db_pool: Arc<dyn std::any::Any + Send + Sync>,
55    app_context: Arc<dyn std::any::Any + Send + Sync>,
56    parameters: HashMap<String, String>,
57}
58
59impl std::fmt::Debug for JobContext {
60    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61        f.debug_struct("JobContext")
62            .field("db_pool", &"<type-erased>")
63            .field("app_context", &"<type-erased>")
64            .field("parameters", &self.parameters)
65            .finish()
66    }
67}
68
69impl JobContext {
70    pub fn new(
71        db_pool: Arc<dyn std::any::Any + Send + Sync>,
72        app_context: Arc<dyn std::any::Any + Send + Sync>,
73    ) -> Self {
74        Self {
75            db_pool,
76            app_context,
77            parameters: HashMap::new(),
78        }
79    }
80
81    pub fn with_parameters(mut self, parameters: HashMap<String, String>) -> Self {
82        self.parameters = parameters;
83        self
84    }
85
86    pub fn db_pool<T: 'static>(&self) -> Option<&T> {
87        self.db_pool.as_ref().downcast_ref::<T>()
88    }
89
90    pub fn app_context<T: 'static>(&self) -> Option<&T> {
91        self.app_context.as_ref().downcast_ref::<T>()
92    }
93
94    pub fn db_pool_arc(&self) -> Arc<dyn std::any::Any + Send + Sync> {
95        Arc::clone(&self.db_pool)
96    }
97
98    pub fn app_context_arc(&self) -> Arc<dyn std::any::Any + Send + Sync> {
99        Arc::clone(&self.app_context)
100    }
101
102    pub const fn parameters(&self) -> &HashMap<String, String> {
103        &self.parameters
104    }
105
106    pub fn get_parameter(&self, key: &str) -> Option<&String> {
107        self.parameters.get(key)
108    }
109}
110
111#[async_trait]
112pub trait Job: Send + Sync + 'static {
113    fn name(&self) -> &'static str;
114
115    fn description(&self) -> &'static str {
116        ""
117    }
118
119    fn schedule(&self) -> &'static str;
120
121    fn tags(&self) -> Vec<&'static str> {
122        vec![]
123    }
124
125    async fn execute(&self, ctx: &JobContext) -> Result<JobResult>;
126
127    fn enabled(&self) -> bool {
128        true
129    }
130
131    fn run_on_startup(&self) -> bool {
132        false
133    }
134}
135
136inventory::collect!(&'static dyn Job);
137
138#[macro_export]
139macro_rules! submit_job {
140    ($job:expr) => {
141        inventory::submit!($job as &'static dyn $crate::Job);
142    };
143}