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