//! Task definition and serialization use serde::{Deserialize, Serialize}; /// Task structure - matches both C FFI and Go queue.Task #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct Task { pub id: String, pub job_name: String, pub priority: i64, pub created_at: i64, pub next_retry: i64, pub status: String, pub retries: u32, } impl Task { /// Create a new task with default values pub fn new(id: impl Into, job_name: impl Into) -> Self { Self { id: id.into(), job_name: job_name.into(), priority: 0, created_at: chrono::Utc::now().timestamp_nanos_opt().unwrap_or(0), next_retry: 0, status: "queued".to_string(), retries: 0, } } /// Serialize to JSON bytes pub fn to_json(&self) -> Result, serde_json::Error> { serde_json::to_vec(self) } /// Deserialize from JSON bytes pub fn from_json(data: &[u8]) -> Result { serde_json::from_slice(data) } /// Check if task is ready to be scheduled pub fn is_ready(&self) -> bool { self.status == "queued" && (self.next_retry == 0 || self.next_retry <= current_time()) } } fn current_time() -> i64 { chrono::Utc::now().timestamp_nanos_opt().unwrap_or(0) } #[cfg(test)] mod tests { use super::*; #[test] fn test_task_serialization() { let task = Task::new("task-1", "test-job"); let json = task.to_json().unwrap(); let deserialized = Task::from_json(&json).unwrap(); assert_eq!(task.id, deserialized.id); assert_eq!(task.job_name, deserialized.job_name); } #[test] fn test_task_ready() { let mut task = Task::new("task-1", "test-job"); task.status = "queued".to_string(); task.next_retry = 0; assert!(task.is_ready()); task.next_retry = current_time() + 1_000_000_000; // 1 second in future assert!(!task.is_ready()); } }