Skip to main content

backbone_bucket/domain/entity/
processing_job.ext.rs

1//! The extension of `processing_job.rs` (hand-written; ADR-0031).
2
3#[allow(unused_imports)]
4use super::*;
5
6impl ProcessingJob {
7
8    // ==========================================================
9    // DDD Entity Methods
10    // ==========================================================
11
12    /// Check if job can be retried (failed and retries remaining)
13    pub fn can_retry(&self) -> bool {
14        self.status == JobStatus::Failed && self.retry_count < self.max_retries
15    }
16
17    /// Increment retry count
18    pub fn increment_retry(&mut self) {
19        self.retry_count += 1;
20        self.metadata.touch();
21    }
22
23    /// Mark job as started
24    pub fn mark_started(&mut self) -> Result<(), JobError> {
25        self.status = JobStatus::Running;
26        self.started_at = Some(Utc::now());
27        self.metadata.touch();
28        Ok(())
29    }
30
31    /// Mark job as completed with result
32    pub fn mark_completed(&mut self, result: serde_json::Value) -> Result<(), JobError> {
33        self.status = JobStatus::Completed;
34        self.result_data = Some(result);
35        self.completed_at = Some(Utc::now());
36        self.metadata.touch();
37        Ok(())
38    }
39
40    /// Mark job as failed with error
41    pub fn mark_failed(&mut self, error: String) -> Result<(), JobError> {
42        self.status = JobStatus::Failed;
43        self.error_message = Some(error);
44        self.metadata.touch();
45        Ok(())
46    }
47
48    /// Cancel the job
49    pub fn cancel(&mut self) -> Result<(), JobError> {
50        self.status = JobStatus::Cancelled;
51        self.metadata.touch();
52        Ok(())
53    }
54
55    /// Get job execution duration (completed_at - started_at if both present)
56    pub fn duration(&self) -> Option<Duration> {
57        match (self.started_at, self.completed_at) {
58            (Some(start), Some(end)) => Some(end - start),
59            _ => None,
60        }
61    }
62
63    /// Check all business invariants
64    pub fn check_invariants(&self) -> Result<(), Vec<&'static str>> {
65        let mut errors = Vec::new();
66        if self.retry_count > self.max_retries {
67            errors.push("retry_count must not exceed max_retries");
68        }
69        if self.status == JobStatus::Running && self.started_at.is_none() {
70            errors.push("running job must have started_at");
71        }
72        if self.status == JobStatus::Completed && self.completed_at.is_none() {
73            errors.push("completed job must have completed_at");
74        }
75        if errors.is_empty() { Ok(()) } else { Err(errors) }
76    }
77}