Skip to main content

systemprompt_provider_contracts/
job.rs

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