Skip to main content

systemprompt_models/services/
scheduler.rs

1//! Scheduler job configuration and the built-in job set.
2//!
3//! Copyright (c) systemprompt.io — Business Source License 1.1.
4//! See <https://systemprompt.io> for licensing details.
5
6use std::collections::HashMap;
7
8use serde::{Deserialize, Serialize};
9use systemprompt_identifiers::UserId;
10pub use systemprompt_provider_contracts::JobScope;
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
13#[serde(deny_unknown_fields)]
14pub struct JobConfig {
15    #[serde(default)]
16    pub extension: Option<String>,
17    pub name: String,
18    #[serde(default)]
19    pub owner: Option<UserId>,
20    #[serde(default = "default_true")]
21    pub enabled: bool,
22    #[serde(default)]
23    pub schedule: Option<String>,
24    #[serde(default)]
25    pub enforce: bool,
26    #[serde(default)]
27    pub parameters: HashMap<String, String>,
28    #[serde(default)]
29    pub scope: Option<JobScope>,
30}
31
32const fn default_true() -> bool {
33    true
34}
35
36impl JobConfig {
37    #[must_use]
38    pub fn new(name: impl Into<String>) -> Self {
39        Self {
40            extension: None,
41            name: name.into(),
42            owner: None,
43            enabled: true,
44            schedule: None,
45            enforce: false,
46            parameters: HashMap::new(),
47            scope: None,
48        }
49    }
50
51    #[must_use]
52    pub const fn with_enforce(mut self) -> Self {
53        self.enforce = true;
54        self
55    }
56
57    #[must_use]
58    pub fn with_owner(mut self, owner: UserId) -> Self {
59        self.owner = Some(owner);
60        self
61    }
62
63    #[must_use]
64    pub fn with_extension(mut self, extension: impl Into<String>) -> Self {
65        self.extension = Some(extension.into());
66        self
67    }
68
69    #[must_use]
70    pub fn with_schedule(mut self, schedule: impl Into<String>) -> Self {
71        self.schedule = Some(schedule.into());
72        self
73    }
74
75    #[must_use]
76    pub fn with_parameters(mut self, parameters: HashMap<String, String>) -> Self {
77        self.parameters = parameters;
78        self
79    }
80
81    #[must_use]
82    pub const fn with_scope(mut self, scope: JobScope) -> Self {
83        self.scope = Some(scope);
84        self
85    }
86
87    #[must_use]
88    pub const fn disabled(mut self) -> Self {
89        self.enabled = false;
90        self
91    }
92}
93
94#[derive(Debug, Clone, Serialize, Deserialize)]
95pub struct SchedulerConfig {
96    #[serde(default = "default_true")]
97    pub enabled: bool,
98    #[serde(default)]
99    pub jobs: Vec<JobConfig>,
100    #[serde(default = "default_bootstrap_jobs")]
101    pub bootstrap_jobs: Vec<String>,
102    #[serde(default = "default_true")]
103    pub distributed_lock: bool,
104}
105
106fn default_bootstrap_jobs() -> Vec<String> {
107    vec!["cleanup_inactive_sessions".to_owned()]
108}
109
110impl SchedulerConfig {
111    #[must_use]
112    pub fn with_system_admin() -> Self {
113        Self {
114            enabled: true,
115            jobs: vec![
116                JobConfig::new("cleanup_anonymous_users")
117                    .with_extension("core")
118                    .with_schedule("0 0 3 * * *")
119                    .with_enforce(),
120                JobConfig::new("cleanup_empty_contexts")
121                    .with_extension("core")
122                    .with_schedule("0 0 * * * *")
123                    .with_enforce(),
124                JobConfig::new("cleanup_inactive_sessions")
125                    .with_extension("core")
126                    .with_schedule("0 0 * * * *"),
127                JobConfig::new("database_cleanup")
128                    .with_extension("core")
129                    .with_schedule("0 0 4 * * *")
130                    .with_enforce(),
131            ],
132            bootstrap_jobs: default_bootstrap_jobs(),
133            distributed_lock: true,
134        }
135    }
136}