1use anyhow::Result;
2
3pub type TaskId = String;
4
5pub trait Runnable<Event, State> {
7 fn id(&self) -> TaskId;
9
10 fn run(&self, state: State) -> impl std::future::Future<Output = Result<Event>> + Send;
13}
14
15use std::{collections::HashMap, sync::Arc};
16
17use async_channel::Sender;
18use serde::{de::DeserializeOwned, Deserialize, Serialize};
19use slog::{debug, error, info, warn, Logger};
20use tokio::sync::RwLock;
21
22use crate::{
23 bridge::{EventBridge, PublishEvents},
24 handler::Startable,
25 network::{NetworkMessage, PeerId},
26 storage::{OwnedTasks, RemoteTasks, TaskAssignments},
27};
28
29const BID_ACCEPTANCE: &str = "bid_acceptance";
30const REQUEST_FOR_BIDS: &str = "request_for_bids";
31const TASK_ERROR: &str = "task_error";
32const TASK_COMPLETE: &str = "task_complete";
33const BID: &str = "bid";
34
35#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct Initialize {
37 pub task: Vec<u8>,
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize)]
41struct RequestForBid {
42 task_id: TaskId,
43 peer_id: PeerId,
44 task: Vec<u8>,
45}
46
47#[derive(Debug, Clone, Serialize, Deserialize)]
48struct Bid {
49 task_id: TaskId,
50 peer_id: PeerId,
51 bid: f64,
52}
53
54#[derive(Debug, Clone, Serialize, Deserialize)]
55struct BidAcceptance {
56 task_id: TaskId,
57 peer_id: PeerId,
58}
59
60#[derive(Debug, Clone, Serialize, Deserialize)]
61struct TaskComplete {
62 task_id: TaskId,
63 peer_id: PeerId,
64 output: Vec<u8>,
65}
66
67#[derive(Debug, Clone, Serialize, Deserialize)]
68struct TaskProgress {
69 task_id: TaskId,
70 peer_id: PeerId,
71 output: Vec<u8>,
72}
73
74#[derive(Debug, Clone, Serialize, Deserialize)]
75struct TaskError {
76 task_id: TaskId,
77 peer_id: PeerId,
78 error: String,
79}
80
81#[derive(Debug, Clone)]
84pub struct DistributedTaskQueue<TTask, TTaskOutput, RunnableState> {
85 logger: Logger,
87
88 local_peer_id: PeerId,
90
91 owned_tasks: OwnedTasks<TTask, TTaskOutput>,
93
94 remote_tasks: RemoteTasks<TTask>,
96
97 task_assignments: TaskAssignments,
99
100 runnable_state: RunnableState,
102
103 bridge: EventBridge,
105}
106
107impl<
108 TTask: Clone + Runnable<TTaskOutput, TRunnableState> + Serialize,
109 TTaskOutput: Clone,
110 TRunnableState: Clone,
111 > DistributedTaskQueue<TTask, TTaskOutput, TRunnableState>
112{
113 pub fn new(
114 logger: &Logger,
115 local_peer_id: &PeerId,
116 runnable_state: &TRunnableState,
117 bridge: &EventBridge,
118 ) -> Self {
119 Self {
120 logger: logger.clone(),
121 local_peer_id: local_peer_id.clone(),
122 owned_tasks: Arc::new(RwLock::new(HashMap::new())),
123 remote_tasks: Arc::new(RwLock::new(HashMap::new())),
124 task_assignments: Arc::new(RwLock::new(HashMap::new())),
125 runnable_state: runnable_state.clone(),
126 bridge: bridge.clone(),
127 }
128 }
129
130 pub async fn submit_task(&self, task: TTask, tx: Sender<TTaskOutput>) -> Result<()> {
131 let mut owned_tasks = self.owned_tasks.write().await;
133 owned_tasks.insert(task.id(), (task.clone(), tx.clone()));
134
135 let request_for_bids = RequestForBid {
137 task_id: task.id(),
138 peer_id: self.local_peer_id.clone(),
139 task: bincode::serialize(&task)?,
140 };
141 self.bridge
142 .publish(PublishEvents::NetworkMessage(NetworkMessage {
143 message_type: REQUEST_FOR_BIDS.to_string(),
144 payload: bincode::serialize(&request_for_bids)?,
145 }))
146 .await?;
147
148 Ok::<_, anyhow::Error>(())
149 }
150}
151
152impl<
153 TTask: Runnable<TTaskOutput, TRunnableState>
154 + Send
155 + Sync
156 + DeserializeOwned
157 + Serialize
158 + Clone
159 + 'static,
160 TTaskOutput: std::fmt::Debug + Clone + Send + Sync + DeserializeOwned + Serialize + 'static,
161 TRunnableState: Clone + Send + Sync + 'static,
162 > Startable for DistributedTaskQueue<TTask, TTaskOutput, TRunnableState>
163{
164 async fn start(&self) -> Result<()> {
165 info!(self.logger, "starting distributed task queue");
166 let handler_rx = self.bridge.subscribe_to_handler().await;
167 loop {
168 let event = handler_rx.recv().await;
170 match event {
171 Ok(event) => {
172 let message = event.message();
173 let logger = self.logger.clone();
174 let bridge = self.bridge.clone();
175 let local_peer_id = self.local_peer_id.clone();
176 let remote_tasks = self.remote_tasks.clone();
177 let owned_tasks = self.owned_tasks.clone();
178 let task_assignments = self.task_assignments.clone();
179 let runnable_state = self.runnable_state.clone();
180 tokio::spawn(async move {
181 let message_type = message.message_type.as_str();
190 info!(logger, "received message"; "message_type" => message_type);
191 match message_type {
192 REQUEST_FOR_BIDS => {
193 let request_for_bid: RequestForBid =
195 bincode::deserialize(&message.payload)?;
196 let task = bincode::deserialize::<TTask>(&request_for_bid.task)?;
197
198 {
200 let mut remote_tasks = remote_tasks.write().await;
201 remote_tasks
202 .insert(request_for_bid.task_id.clone(), task.clone());
203 }
204
205 let bid = Bid {
207 task_id: request_for_bid.task_id.clone(),
208 peer_id: local_peer_id.clone(),
209 bid: 1.0,
210 };
211 bridge
212 .publish(crate::bridge::PublishEvents::NetworkMessage(
213 NetworkMessage {
214 message_type: BID.to_string(),
215 payload: bincode::serialize(&bid)?,
216 },
217 ))
218 .await?;
219
220 Ok::<_, anyhow::Error>(())
221 }
222 BID => {
223 let bid: Bid = bincode::deserialize(&message.payload)?;
225
226 if owned_tasks.read().await.get(&bid.task_id).is_none() {
228 debug!(logger, "received bid for unknown task"; "task_id" => bid.task_id);
229 return Ok(());
230 }
231
232 if task_assignments.read().await.contains_key(&bid.task_id) {
234 debug!(logger, "received bid for already assigned task"; "task_id" => bid.task_id);
235 return Ok(());
236 }
237
238 {
240 let mut task_assignments = task_assignments.write().await;
241 task_assignments
242 .insert(bid.task_id.clone(), bid.peer_id.clone());
243 }
244
245 if let Err(e) = bridge
247 .publish(crate::bridge::PublishEvents::NetworkMessage(
248 NetworkMessage {
249 message_type: BID_ACCEPTANCE.to_string(),
250 payload: bincode::serialize(&BidAcceptance {
251 task_id: bid.task_id.clone(),
252 peer_id: bid.peer_id.clone(),
253 })?,
254 },
255 ))
256 .await
257 {
258 warn!(logger, "failed to emit bid acceptance event"; "error" => e.to_string());
259 return Ok(());
260 };
261
262 Ok(())
263 }
264 BID_ACCEPTANCE => {
265 let bid_acceptance: BidAcceptance =
266 bincode::deserialize(&message.payload)?;
267
268 if bid_acceptance.peer_id != local_peer_id {
270 debug!(logger, "received bid acceptance for another node"; "peer_id" => bid_acceptance.peer_id);
271 return Ok(());
272 }
273
274 let task = {
276 let mut remote_tasks = remote_tasks.write().await;
277 remote_tasks.remove(&bid_acceptance.task_id)
278 };
279
280 if task.is_none() {
282 error!(logger, "task not found for bid acceptance"; "task_id" => bid_acceptance.task_id);
283 return Ok(());
284 }
285 let task = task.unwrap();
286
287 let output = task.run(runnable_state.clone()).await?;
289 info!(logger, "task complete"; "task_id" => task.id());
290
291 bridge
293 .publish(crate::bridge::PublishEvents::NetworkMessage(
294 NetworkMessage {
295 message_type: TASK_COMPLETE.to_string(),
296 payload: bincode::serialize(&TaskComplete {
297 task_id: task.id(),
298 peer_id: local_peer_id.clone(),
299 output: bincode::serialize(&output)?,
300 })?,
301 },
302 ))
303 .await?;
304
305 Ok(())
306 }
307 TASK_COMPLETE => {
308 let task_complete: TaskComplete =
310 bincode::deserialize(&message.payload)?;
311
312 let task = {
314 let mut owned_tasks = owned_tasks.write().await;
315 owned_tasks.remove(&task_complete.task_id)
316 };
317 if task.is_none() {
318 debug!(logger, "task not found for task complete"; "task_id" => task_complete.task_id);
319 return Ok(());
320 }
321
322 let (_, tx) = task.unwrap();
324 tx.send(bincode::deserialize(&task_complete.output)?)
325 .await?;
326
327 {
329 let mut task_assignments = task_assignments.write().await;
330 task_assignments.remove(&task_complete.task_id);
331 }
332
333 Ok(())
334 }
335 TASK_ERROR => {
336 let task_error =
337 bincode::deserialize::<TaskError>(&message.payload)?;
338 if owned_tasks.read().await.get(&task_error.task_id).is_none() {
339 debug!(logger, "received task error for unknown task"; "task_id" => task_error.task_id);
340 return Ok(());
341 }
342 Ok(())
343 }
344 _ => {
345 debug!(logger, "received unknown message type"; "message_type" => message_type);
346 Ok(())
347 }
348 }
349 })
350 }
351 Err(e) => {
352 error!(self.logger, "failed to receive handler event"; "error" => e.to_string());
353 return Ok(());
354 }
355 };
356 }
357 }
358}