Skip to main content

mocra_core/common/processors/
processor.rs

1#![allow(unused)]
2
3use crate::errors::error::{Error, Result};
4use async_trait::async_trait;
5use std::collections::HashMap;
6use std::sync::Arc;
7use tokio::sync::RwLock;
8
9/// Retry policy.
10#[derive(Debug, Clone)]
11pub struct RetryPolicy {
12    /// Maximum retry attempts.
13    pub max_retries: u32,
14    /// Initial retry delay in milliseconds.
15    pub retry_delay: u64,
16    /// Current retry count.
17    pub current_retry: u32,
18    /// Retry reason.
19    pub reason: Option<String>,
20    /// Extra metadata.
21    pub meta: serde_json::Value,
22}
23impl Default for RetryPolicy {
24    fn default() -> Self {
25        Self {
26            max_retries: 3,
27            retry_delay: 2000,
28            current_retry: 0,
29            reason: None,
30            meta: Default::default(),
31        }
32    }
33}
34
35impl RetryPolicy {
36    /// Returns `true` when another retry should be attempted.
37    pub fn should_retry(&self) -> bool {
38        self.current_retry < self.max_retries
39    }
40    /// Calculates delay before the next retry.
41    pub fn next_retry_delay(&self) -> u64 {
42        self.retry_delay * (self.current_retry + 1) as u64
43    }
44    /// Increments retry count.
45    pub fn increment_retry(&mut self) {
46        self.current_retry += 1;
47    }
48    /// Resets retry state.
49    pub fn reset(&mut self) {
50        self.current_retry = 0;
51        self.retry_delay = 2000;
52    }
53    /// Advances retry state and returns the delay for the next retry.
54    pub async fn delay_next_retry(&mut self) -> Option<u64> {
55        if !self.should_retry() {
56            return None;
57        }
58        self.increment_retry();
59        let delay = self.next_retry_delay();
60        Some(delay)
61    }
62
63    /// Adds a metadata entry.
64    pub fn with_meta(mut self, key: &str, value: serde_json::Value) -> Self {
65        if let serde_json::Value::Object(ref mut map) = self.meta {
66            map.insert(key.to_string(), value);
67        }
68        self
69    }
70    /// Sets retry reason.
71    pub fn with_reason(mut self, reason: String) -> Self {
72        self.reason = Some(reason);
73        self
74    }
75    /// Sets the base retry delay in milliseconds.
76    pub fn with_delay(mut self, delay_ms: u64) -> Self {
77        self.retry_delay = delay_ms;
78        self
79    }
80}
81
82/// Processor execution result.
83#[derive(Debug)]
84pub enum ProcessorResult<T> {
85    /// Processing succeeded.
86    Success(T),
87    /// Processing failed, but can be retried.
88    RetryableFailure(RetryPolicy),
89    /// Processing failed and is not retryable.
90    FatalFailure(Error),
91}
92
93impl<T> ProcessorResult<T> {
94    pub fn is_success(&self) -> bool {
95        matches!(self, ProcessorResult::Success(_))
96    }
97
98    pub fn is_failure(&self) -> bool {
99        matches!(
100            self,
101            ProcessorResult::RetryableFailure(_) | ProcessorResult::FatalFailure(_)
102        )
103    }
104
105    pub fn is_retryable(&self) -> bool {
106        matches!(self, ProcessorResult::RetryableFailure(_))
107    }
108}
109
110/// Processor execution context.
111#[derive(Debug, Clone)]
112pub struct ProcessorContext {
113    /// Thread-safe metadata.
114    pub metadata: Arc<RwLock<HashMap<String, serde_json::Value>>>,
115    /// Retry policy.
116    pub retry_policy: Option<RetryPolicy>,
117    /// Creation timestamp.
118    pub created_at: u64,
119    /// Step timeout in milliseconds.
120    pub step_timeout_ms: Option<u64>,
121    /// Whether execution has been cancelled.
122    pub cancelled: bool,
123}
124
125impl Default for ProcessorContext {
126    fn default() -> Self {
127        Self {
128            metadata: Default::default(),
129            retry_policy: None,
130            created_at: std::time::SystemTime::now()
131                .duration_since(std::time::UNIX_EPOCH)
132                .unwrap()
133                .as_secs(),
134            step_timeout_ms: None,
135            cancelled: false,
136        }
137    }
138}
139
140impl ProcessorContext {
141    pub fn new() -> Self {
142        Self::default()
143    }
144    pub async fn with_metadata(mut self, key: String, value: serde_json::Value) -> Self {
145        self.metadata.write().await.insert(key, value);
146        self
147    }
148
149    pub fn with_retry_policy(mut self, retry_policy: RetryPolicy) -> Self {
150        self.retry_policy = Some(retry_policy);
151        self
152    }
153
154    pub fn with_step_timeout_ms(mut self, ms: u64) -> Self {
155        self.step_timeout_ms = Some(ms);
156        self
157    }
158
159    pub fn cancel(mut self) -> Self {
160        self.cancelled = true;
161        self
162    }
163}
164
165/// Base processor trait.
166#[async_trait]
167pub trait ProcessorTrait<Input, Output>: Send + Sync {
168    /// Processor name.
169    fn name(&self) -> &'static str;
170
171    /// Processes input data.
172    async fn process(&self, input: Input, context: ProcessorContext) -> ProcessorResult<Output>;
173
174    /// Optional pre-processing hook.
175    async fn pre_process(&self, _input: &Input, _context: &ProcessorContext) -> Result<()> {
176        Ok(())
177    }
178
179    /// Optional post-processing hook.
180    async fn post_process(
181        &self,
182        _input: &Input,
183        _output: &Output,
184        _context: &ProcessorContext,
185    ) -> Result<()> {
186        Ok(())
187    }
188
189    /// Optional error handling hook.
190    async fn handle_error(
191        &self,
192        _input: &Input,
193        _error: Error,
194        _context: &ProcessorContext,
195    ) -> ProcessorResult<Output> {
196        ProcessorResult::FatalFailure(_error)
197    }
198
199    /// Optional predicate to decide whether this input should be processed.
200    async fn should_process(&self, _input: &Input, _context: &ProcessorContext) -> bool {
201        true
202    }
203}
204
205/// Configurable processor trait.
206#[async_trait]
207pub trait ConfigurableProcessor<Input, Output, Config>: ProcessorTrait<Input, Output> {
208    /// Applies configuration.
209    async fn apply_config(&mut self, config: Config) -> Result<()>;
210
211    /// Returns current configuration.
212    fn get_config(&self) -> Option<&Config>;
213}