use crate::error::{Result, ValidationError};
use crate::state::{TaskRecord, TaskState};
use std::collections::HashMap;
#[derive(Debug, Default, Clone)]
pub struct StateValidator;
#[derive(Debug, Default, PartialEq, Eq)]
pub struct RepairReport {
pub reset_running: Vec<String>,
pub clamped_attempts: Vec<String>,
}
impl RepairReport {
pub fn is_clean(&self) -> bool {
self.reset_running.is_empty() && self.clamped_attempts.is_empty()
}
}
impl StateValidator {
pub fn new() -> Self {
StateValidator
}
pub fn validate_transition(&self, from: TaskState, to: TaskState) -> Result<()> {
if from.can_transition_to(to) {
Ok(())
} else {
Err(ValidationError::InvalidTransition {
from: from.to_string(),
to: to.to_string(),
}
.into())
}
}
pub fn repair(
&self,
records: &mut HashMap<String, TaskRecord>,
max_attempts: u32,
) -> RepairReport {
let mut report = RepairReport::default();
for (id, record) in records.iter_mut() {
match record.state {
TaskState::Running | TaskState::Retrying => {
record.state = if record.attempts < max_attempts {
TaskState::Pending
} else {
TaskState::Failed
};
record.started_at = None;
record.updated_at = crate::state::now_millis();
report.reset_running.push(id.clone());
}
_ => {}
}
if record.attempts > max_attempts {
record.attempts = max_attempts;
report.clamped_attempts.push(id.clone());
}
}
report
}
}