Skip to main content

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}