Skip to main content

rustapi_jobs/backend/
memory.rs

1use super::{JobBackend, JobRequest};
2use crate::error::{JobError, Result};
3use async_trait::async_trait;
4use std::collections::VecDeque;
5use std::sync::{Arc, Mutex};
6
7/// In-memory job backend (not persistent, for testing/dev)
8#[derive(Debug, Clone, Default)]
9pub struct InMemoryBackend {
10    queue: Arc<Mutex<VecDeque<JobRequest>>>,
11    // In a real system we'd track processing jobs separately for reliability
12}
13
14impl InMemoryBackend {
15    pub fn new() -> Self {
16        Self::default()
17    }
18}
19
20#[async_trait]
21impl JobBackend for InMemoryBackend {
22    async fn push(&self, job: JobRequest) -> Result<()> {
23        let mut q = self
24            .queue
25            .lock()
26            .map_err(|_| JobError::BackendError("Lock poisoned".to_string()))?;
27        q.push_back(job);
28        Ok(())
29    }
30
31    async fn pop(&self) -> Result<Option<JobRequest>> {
32        let mut q = self
33            .queue
34            .lock()
35            .map_err(|_| JobError::BackendError("Lock poisoned".to_string()))?;
36
37        // Simple FIFO for now, ignoring run_at logic complexity for basic in-memory
38        // In reality we should scan for ready jobs
39        if let Some(job) = q.front() {
40            if let Some(run_at) = job.run_at {
41                if run_at > chrono::Utc::now() {
42                    return Ok(None);
43                }
44            }
45        } else {
46            return Ok(None);
47        }
48
49        Ok(q.pop_front())
50    }
51
52    async fn complete(&self, _job_id: &str) -> Result<()> {
53        // No-op for simple in-memory queue that removes on pop
54        Ok(())
55    }
56
57    async fn fail(&self, _job_id: &str, _error: &str) -> Result<()> {
58        // In a real implementation we might move to DLQ or re-queue
59        Ok(())
60    }
61}