1use std::{fmt, str::FromStr, time::Duration};
4
5use serde::{Deserialize, Serialize};
6use serde_json::{Map, Value as JsonValue};
7use uuid::Uuid;
8
9pub type Json = JsonValue;
11
12pub type JsonObject = Map<String, Json>;
14
15#[derive(
20 Debug, Clone, Copy, Serialize, Deserialize, sqlx::Type, PartialEq, Eq, Hash, PartialOrd, Ord,
21)]
22#[serde(transparent)]
23#[sqlx(transparent)]
24pub struct TaskId(Uuid);
25
26impl TaskId {
27 pub const fn from_uuid(value: Uuid) -> Self {
29 Self(value)
30 }
31
32 pub const fn into_uuid(self) -> Uuid {
34 self.0
35 }
36}
37
38impl From<Uuid> for TaskId {
39 fn from(value: Uuid) -> Self {
40 Self::from_uuid(value)
41 }
42}
43
44impl From<TaskId> for Uuid {
45 fn from(value: TaskId) -> Self {
46 value.into_uuid()
47 }
48}
49
50impl fmt::Display for TaskId {
51 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52 self.0.fmt(f)
53 }
54}
55
56impl FromStr for TaskId {
57 type Err = uuid::Error;
58
59 fn from_str(value: &str) -> Result<Self, Self::Err> {
60 value.parse().map(Self::from_uuid)
61 }
62}
63
64#[derive(
68 Debug, Clone, Copy, Serialize, Deserialize, sqlx::Type, PartialEq, Eq, Hash, PartialOrd, Ord,
69)]
70#[serde(transparent)]
71#[sqlx(transparent)]
72pub struct RunId(Uuid);
73
74impl RunId {
75 pub const fn from_uuid(value: Uuid) -> Self {
77 Self(value)
78 }
79
80 pub const fn into_uuid(self) -> Uuid {
82 self.0
83 }
84}
85
86impl From<Uuid> for RunId {
87 fn from(value: Uuid) -> Self {
88 Self::from_uuid(value)
89 }
90}
91
92impl From<RunId> for Uuid {
93 fn from(value: RunId) -> Self {
94 value.into_uuid()
95 }
96}
97
98impl fmt::Display for RunId {
99 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100 self.0.fmt(f)
101 }
102}
103
104impl FromStr for RunId {
105 type Err = uuid::Error;
106
107 fn from_str(value: &str) -> Result<Self, Self::Err> {
108 value.parse().map(Self::from_uuid)
109 }
110}
111
112#[derive(Debug, Clone, Copy, PartialEq)]
127pub enum RetryStrategy {
128 Fixed {
130 delay: Duration,
132 },
133
134 Exponential {
136 initial_delay: Duration,
138 factor: f64,
140 max_delay: Option<Duration>,
142 },
143
144 None,
146}
147
148impl RetryStrategy {
149 pub const fn fixed(delay: Duration) -> Self {
151 Self::Fixed { delay }
152 }
153
154 pub const fn exponential(
156 initial_delay: Duration,
157 factor: f64,
158 max_delay: Option<Duration>,
159 ) -> Self {
160 Self::Exponential { initial_delay, factor, max_delay }
161 }
162
163 pub const fn none() -> Self {
165 Self::None
166 }
167}
168
169#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
176pub struct CancellationPolicy {
177 pub(crate) max_duration: Option<Duration>,
179
180 pub(crate) max_delay: Option<Duration>,
182}
183
184impl CancellationPolicy {
185 pub const fn new() -> Self {
187 Self { max_duration: None, max_delay: None }
188 }
189
190 #[must_use]
192 pub const fn max_duration(mut self, duration: Duration) -> Self {
193 self.max_duration = Some(duration);
194 self
195 }
196
197 #[must_use]
199 pub const fn max_delay(mut self, delay: Duration) -> Self {
200 self.max_delay = Some(delay);
201 self
202 }
203}
204
205#[derive(Debug, Clone, Default)]
207pub(crate) struct SpawnConfig {
208 pub max_attempts: Option<u32>,
210
211 pub retry_strategy: Option<RetryStrategy>,
213
214 pub headers: Option<JsonObject>,
216
217 pub cancellation: Option<CancellationPolicy>,
219
220 pub idempotency_key: Option<String>,
222}
223
224#[derive(Debug, Clone, Copy)]
226pub(crate) struct SpawnResult {
227 pub task_id: TaskId,
229
230 pub created: bool,
232}
233
234#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
239pub struct QueuePolicyOptions {
240 pub(crate) cleanup_ttl: Option<Duration>,
242
243 pub(crate) cleanup_limit: Option<u32>,
245}
246
247impl QueuePolicyOptions {
248 pub const fn new() -> Self {
250 Self { cleanup_ttl: None, cleanup_limit: None }
251 }
252
253 #[must_use]
255 pub const fn cleanup_ttl(mut self, cleanup_ttl: Duration) -> Self {
256 self.cleanup_ttl = Some(cleanup_ttl);
257 self
258 }
259
260 #[must_use]
262 pub const fn cleanup_limit(mut self, cleanup_limit: u32) -> Self {
263 self.cleanup_limit = Some(cleanup_limit);
264 self
265 }
266}
267
268#[derive(Debug, Clone, PartialEq, Eq)]
270pub struct QueuePolicy {
271 pub queue_name: String,
273
274 pub cleanup_ttl: Duration,
276
277 pub cleanup_limit: u32,
279}
280
281#[derive(Debug, Clone, PartialEq, Eq)]
283pub struct QueueCleanup {
284 pub queue_name: String,
286
287 pub tasks_deleted: u32,
289}
290
291#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
293#[serde(rename_all = "lowercase")]
294pub enum TaskState {
295 Pending,
297
298 Running,
300
301 Sleeping,
303
304 Completed,
306
307 Failed,
309
310 Cancelled,
312}
313
314#[derive(Debug, Clone, PartialEq, Eq)]
316pub(crate) enum TaskResultSnapshot {
317 Pending,
319
320 Running,
322
323 Sleeping,
325
326 Completed {
328 result: Json,
330 },
331
332 Failed {
334 failure: Json,
336 },
337
338 Cancelled,
340}
341
342impl TaskResultSnapshot {
343 pub(crate) const fn is_terminal(&self) -> bool {
345 matches!(self, Self::Completed { .. } | Self::Failed { .. } | Self::Cancelled)
346 }
347}
348
349#[derive(Debug, Clone)]
351pub(crate) struct ClaimedTask {
352 pub(crate) run_id: RunId,
354
355 pub(crate) task_id: TaskId,
357
358 pub(crate) task_name: String,
360
361 pub(crate) attempt: u32,
363
364 pub(crate) params: Json,
366
367 pub(crate) headers: Option<JsonObject>,
369}