Skip to main content

reinhardt_tasks/
backend.rs

1//! Task backend implementations
2
3use crate::{Task, TaskId, TaskStatus, registry::SerializedTask};
4use async_trait::async_trait;
5use thiserror::Error;
6
7/// Errors that can occur during task execution in a backend.
8#[derive(Debug, Error)]
9pub enum TaskExecutionError {
10	/// The task failed during execution.
11	#[error("Task execution failed: {0}")]
12	ExecutionFailed(String),
13
14	/// The requested task was not found in the backend.
15	#[error("Task not found: {0}")]
16	NotFound(TaskId),
17
18	/// A backend-specific error occurred.
19	#[error("Backend error: {0}")]
20	BackendError(String),
21}
22
23/// Alias for `TaskStatus` used in result contexts.
24pub type ResultStatus = TaskStatus;
25/// Alias for `TaskStatus` used in task result contexts.
26pub type TaskResultStatus = TaskStatus;
27
28/// Trait for task queue backends that handle enqueueing, dequeueing, and status tracking.
29#[async_trait]
30pub trait TaskBackend: Send + Sync {
31	/// Enqueues a task and returns its assigned ID.
32	async fn enqueue(&self, task: Box<dyn Task>) -> Result<TaskId, TaskExecutionError>;
33	/// Dequeues the next available task ID, if any.
34	async fn dequeue(&self) -> Result<Option<TaskId>, TaskExecutionError>;
35	/// Retrieves the current status of a task by its ID.
36	async fn get_status(&self, task_id: TaskId) -> Result<TaskStatus, TaskExecutionError>;
37	/// Updates the status of a task.
38	async fn update_status(
39		&self,
40		task_id: TaskId,
41		status: TaskStatus,
42	) -> Result<(), TaskExecutionError>;
43
44	/// Get serialized task data by task ID
45	///
46	/// Returns the task data if found, None otherwise.
47	async fn get_task_data(
48		&self,
49		task_id: TaskId,
50	) -> Result<Option<SerializedTask>, TaskExecutionError>;
51
52	/// Returns the name of this backend implementation.
53	fn backend_name(&self) -> &str;
54}
55
56/// Registry of available task backends.
57pub struct TaskBackends;
58
59impl TaskBackends {
60	/// Creates a new empty backend registry.
61	pub fn new() -> Self {
62		Self
63	}
64}
65
66impl Default for TaskBackends {
67	fn default() -> Self {
68		Self::new()
69	}
70}
71
72/// A no-op backend that discards all tasks. Useful for testing.
73pub struct DummyBackend;
74
75impl DummyBackend {
76	/// Creates a new dummy backend.
77	pub fn new() -> Self {
78		Self
79	}
80}
81
82impl Default for DummyBackend {
83	fn default() -> Self {
84		Self::new()
85	}
86}
87
88#[async_trait]
89impl TaskBackend for DummyBackend {
90	async fn enqueue(&self, _task: Box<dyn Task>) -> Result<TaskId, TaskExecutionError> {
91		Ok(TaskId::new())
92	}
93
94	async fn dequeue(&self) -> Result<Option<TaskId>, TaskExecutionError> {
95		Ok(None)
96	}
97
98	async fn get_status(&self, _task_id: TaskId) -> Result<TaskStatus, TaskExecutionError> {
99		Ok(TaskStatus::Success)
100	}
101
102	async fn update_status(
103		&self,
104		_task_id: TaskId,
105		_status: TaskStatus,
106	) -> Result<(), TaskExecutionError> {
107		Ok(())
108	}
109
110	async fn get_task_data(
111		&self,
112		_task_id: TaskId,
113	) -> Result<Option<SerializedTask>, TaskExecutionError> {
114		// DummyBackend doesn't store task data
115		Ok(None)
116	}
117
118	fn backend_name(&self) -> &str {
119		"dummy"
120	}
121}
122
123/// A backend that executes tasks immediately upon enqueueing.
124pub struct ImmediateBackend;
125
126impl ImmediateBackend {
127	/// Creates a new immediate backend.
128	pub fn new() -> Self {
129		Self
130	}
131}
132
133impl Default for ImmediateBackend {
134	fn default() -> Self {
135		Self::new()
136	}
137}
138
139#[async_trait]
140impl TaskBackend for ImmediateBackend {
141	async fn enqueue(&self, _task: Box<dyn Task>) -> Result<TaskId, TaskExecutionError> {
142		Ok(TaskId::new())
143	}
144
145	async fn dequeue(&self) -> Result<Option<TaskId>, TaskExecutionError> {
146		Ok(None)
147	}
148
149	async fn get_status(&self, _task_id: TaskId) -> Result<TaskStatus, TaskExecutionError> {
150		Ok(TaskStatus::Success)
151	}
152
153	async fn update_status(
154		&self,
155		_task_id: TaskId,
156		_status: TaskStatus,
157	) -> Result<(), TaskExecutionError> {
158		Ok(())
159	}
160
161	async fn get_task_data(
162		&self,
163		_task_id: TaskId,
164	) -> Result<Option<SerializedTask>, TaskExecutionError> {
165		// ImmediateBackend doesn't store task data
166		Ok(None)
167	}
168
169	fn backend_name(&self) -> &str {
170		"immediate"
171	}
172}