apalis_sqlite/config.rs
1use std::time::Duration;
2
3use apalis_core::backend::queue::Queue;
4use serde::{Deserialize, Serialize};
5
6/// Configuration for a worker's queue, batching, and liveness detection.
7///
8/// `Config` controls how jobs are fetched from a queue and how worker
9/// liveness is monitored.
10///
11/// # Defaults
12///
13/// - `batch_size`: `10`
14/// - `heartbeat_interval`: `30` seconds
15/// - `missed_heartbeats`: `2`
16/// - `queue`: `"default"`
17/// - `database_url`: `None`
18/// - `lock_tasks`: `true`
19/// - `persist_results`: `true`
20#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
21pub struct Config {
22 /// The maximum number of jobs fetched in a single batch.
23 ///
24 /// Must be greater than zero.
25 #[serde(default = "default_batch_size")]
26 pub batch_size: usize,
27
28 /// The interval between worker heartbeats.
29 #[serde(default = "default_heartbeat_interval")]
30 pub heartbeat_interval: Duration,
31
32 /// The number of missed heartbeats allowed before a worker is
33 /// considered dead.
34 #[serde(default = "default_missed_heartbeats")]
35 pub missed_heartbeats: usize,
36
37 /// The queue from which jobs are consumed.
38 pub queue: Queue,
39
40 /// An optional database URL used by the worker.
41 pub database_url: Option<String>,
42
43 /// Whether tasks should be locked while being processed.
44 #[serde(default = "default_events")]
45 pub lock_tasks: bool,
46
47 /// Whether job results should be persisted.
48 #[serde(default = "default_events")]
49 pub persist_results: bool,
50}
51
52impl Default for Config {
53 fn default() -> Self {
54 Self {
55 batch_size: 10,
56 heartbeat_interval: Duration::from_secs(30),
57 missed_heartbeats: 2,
58 queue: Queue::from("default"),
59 database_url: None,
60 lock_tasks: true,
61 persist_results: true,
62 }
63 }
64}
65
66fn default_batch_size() -> usize {
67 10
68}
69
70fn default_heartbeat_interval() -> Duration {
71 Duration::from_secs(30)
72}
73
74fn default_missed_heartbeats() -> usize {
75 2
76}
77
78fn default_events() -> bool {
79 true
80}
81
82impl Config {
83 /// Sets the maximum number of jobs to fetch in a single batch.
84 ///
85 /// Larger batches can improve throughput by reducing the number of
86 /// queue operations, while smaller batches can reduce memory usage
87 /// and improve job distribution between workers.
88 ///
89 /// # Panics
90 ///
91 /// Panics if `size` is `0`.
92 ///
93 /// # Examples
94 ///
95 /// ```
96 /// use apalis_sqlite::Config;
97 ///
98 /// let config = Config::default().batch_size(50);
99 ///
100 /// assert_eq!(config.batch_size, 50);
101 /// ```
102 #[must_use]
103 pub fn batch_size(mut self, size: usize) -> Self {
104 assert!(size > 0, "batch size cannot be 0");
105 self.batch_size = size;
106 self
107 }
108
109 /// Sets the interval between worker heartbeats.
110 ///
111 /// A shorter interval detects failed workers sooner but produces
112 /// heartbeat activity more frequently.
113 ///
114 /// # Examples
115 ///
116 /// ```
117 /// use std::time::Duration;
118 /// use apalis_sqlite::Config;
119 ///
120 /// let config = Config::default()
121 /// .heartbeat_interval(Duration::from_secs(15));
122 ///
123 /// assert_eq!(config.heartbeat_interval, Duration::from_secs(15));
124 /// ```
125 #[must_use]
126 pub fn heartbeat_interval(mut self, interval: Duration) -> Self {
127 self.heartbeat_interval = interval;
128 self
129 }
130
131 /// Sets the queue from which jobs are consumed.
132 ///
133 /// # Examples
134 ///
135 /// ```
136 /// # use apalis_sqlite::Config;
137 /// let config = Config::default()
138 /// .queue("high-priority");
139 ///
140 /// assert_eq!(config.queue.as_ref(), "high-priority");
141 /// ```
142 #[must_use]
143 pub fn queue(mut self, queue: impl AsRef<str>) -> Self {
144 self.queue = Queue::from(queue.as_ref());
145 self
146 }
147
148 /// Sets the number of missed heartbeats allowed before a worker is
149 /// considered dead.
150 ///
151 /// This value works together with [`Self::heartbeat_interval`].
152 /// For example, a 30-second heartbeat interval with `2` missed
153 /// heartbeats results in an orphan timeout of 60 seconds.
154 ///
155 /// # Examples
156 ///
157 /// ```
158 /// use apalis_sqlite::Config;
159 ///
160 /// let config = Config::default().missed_heartbeats(3);
161 ///
162 /// assert_eq!(config.missed_heartbeats, 3);
163 /// assert_eq!(
164 /// config.orphaned_duration(),
165 /// std::time::Duration::from_secs(90)
166 /// );
167 /// ```
168 #[must_use]
169 pub fn missed_heartbeats(mut self, missed_heartbeats: usize) -> Self {
170 self.missed_heartbeats = missed_heartbeats;
171 self
172 }
173
174 /// Sets the database URL used by the worker.
175 ///
176 /// # Examples
177 ///
178 /// ```
179 /// use apalis_sqlite::Config;
180 ///
181 /// let config = Config::default()
182 /// .database_url(":memory:");
183 ///
184 /// assert_eq!(
185 /// config.database_url.as_deref(),
186 /// Some(":memory:")
187 /// );
188 /// ```
189 #[must_use]
190 pub fn database_url(mut self, database_url: impl Into<String>) -> Self {
191 self.database_url = Some(database_url.into());
192 self
193 }
194
195 /// Enables or disables task locking.
196 ///
197 /// When enabled, tasks are locked while being processed to prevent
198 /// multiple workers from processing the same task concurrently.
199 ///
200 /// # Examples
201 ///
202 /// ```
203 /// use apalis_sqlite::Config;
204 ///
205 /// let config = Config::default().lock_tasks(false);
206 ///
207 /// assert!(!config.lock_tasks);
208 /// ```
209 #[must_use]
210 pub fn lock_tasks(mut self, lock_tasks: bool) -> Self {
211 self.lock_tasks = lock_tasks;
212 self
213 }
214
215 /// Enables or disables result persistence.
216 ///
217 /// When enabled, results produced by completed jobs are persisted.
218 ///
219 /// # Examples
220 ///
221 /// ```
222 /// use apalis_sqlite::Config;
223 ///
224 /// let config = Config::default().persist_results(false);
225 ///
226 /// assert!(!config.persist_results);
227 /// ```
228 #[must_use]
229 pub fn persist_results(mut self, persist_results: bool) -> Self {
230 self.persist_results = persist_results;
231 self
232 }
233
234 /// Returns the amount of time after which a worker may be considered
235 /// orphaned.
236 ///
237 /// The duration is calculated as:
238 ///
239 /// ```text
240 /// heartbeat_interval × missed_heartbeats
241 /// ```
242 #[must_use]
243 pub fn orphaned_duration(&self) -> Duration {
244 self.heartbeat_interval * self.missed_heartbeats as u32
245 }
246}