1use super::window::{EventWindow, Watermark, WindowConfig, WindowResult};
10use crate::StreamEvent;
11use anyhow::{anyhow, Result};
12use chrono::{DateTime, Duration as ChronoDuration, Utc};
13use serde::{Deserialize, Serialize};
14use std::collections::{HashMap, VecDeque};
15use tracing::{debug, info, warn};
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct ProcessorConfig {
20 pub max_windows: usize,
22 pub max_late_events: usize,
24 pub watermark_interval: ChronoDuration,
26 pub enable_stats: bool,
28 pub memory_limit: Option<usize>,
30}
31
32impl Default for ProcessorConfig {
33 fn default() -> Self {
34 Self {
35 max_windows: 1000,
36 max_late_events: 10000,
37 watermark_interval: ChronoDuration::seconds(1),
38 enable_stats: true,
39 memory_limit: Some(1024 * 1024 * 100), }
41 }
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize)]
46pub struct ProcessorStats {
47 pub events_processed: u64,
49 pub windows_created: u64,
51 pub windows_triggered: u64,
53 pub late_events: u64,
55 pub dropped_events: u64,
57 pub start_time: DateTime<Utc>,
59 pub last_processing_time: DateTime<Utc>,
61 pub avg_latency_ms: f64,
63 pub peak_memory_usage: usize,
65}
66
67impl Default for ProcessorStats {
68 fn default() -> Self {
69 let now = Utc::now();
70 Self {
71 events_processed: 0,
72 windows_created: 0,
73 windows_triggered: 0,
74 late_events: 0,
75 dropped_events: 0,
76 start_time: now,
77 last_processing_time: now,
78 avg_latency_ms: 0.0,
79 peak_memory_usage: 0,
80 }
81 }
82}
83
84pub struct EventProcessor {
86 windows: HashMap<String, EventWindow>,
87 watermark: DateTime<Utc>,
88 late_events: VecDeque<(StreamEvent, DateTime<Utc>)>,
89 stats: ProcessorStats,
90 config: ProcessorConfig,
91 watermark_manager: Watermark,
92}
93
94impl EventProcessor {
95 pub fn new(config: ProcessorConfig) -> Self {
97 Self {
98 windows: HashMap::new(),
99 watermark: Utc::now(),
100 late_events: VecDeque::new(),
101 stats: ProcessorStats::default(),
102 config,
103 watermark_manager: Watermark::default(),
104 }
105 }
106
107 pub fn create_window(&mut self, config: WindowConfig) -> Result<String> {
109 let window = EventWindow::new(config);
110 let window_id = window.id().to_string();
111
112 if let Some(limit) = self.config.memory_limit {
114 if self.estimate_memory_usage() > limit {
115 return Err(anyhow!("Memory limit exceeded, cannot create new window"));
116 }
117 }
118
119 if self.windows.len() >= self.config.max_windows {
121 warn!("Maximum number of windows reached, removing oldest window");
122 self.remove_oldest_window();
123 }
124
125 self.windows.insert(window_id.clone(), window);
126 self.stats.windows_created += 1;
127
128 info!("Created new window: {}", window_id);
129 Ok(window_id)
130 }
131
132 pub fn process_event(&mut self, event: StreamEvent) -> Result<Vec<WindowResult>> {
134 let start_time = std::time::Instant::now();
135 let mut results = Vec::new();
136
137 self.update_watermark(&event)?;
139
140 if self.is_late_event(&event) {
142 self.handle_late_event(event)?;
143 return Ok(results);
144 }
145
146 let mut windows_to_trigger = Vec::new();
148
149 for (window_id, window) in &mut self.windows {
150 if let Err(e) = window.add_event(event.clone()) {
151 warn!("Failed to add event to window {}: {}", window_id, e);
152 continue;
153 }
154
155 if window.should_trigger(self.watermark) {
157 windows_to_trigger.push(window_id.clone());
158 }
159 }
160
161 for window_id in windows_to_trigger {
163 let result = self.trigger_window(&window_id)?;
164 results.push(result);
165 }
166
167 self.update_stats(start_time);
169
170 Ok(results)
171 }
172
173 fn trigger_window(&mut self, window_id: &str) -> Result<WindowResult> {
175 let window = self
176 .windows
177 .get(window_id)
178 .ok_or_else(|| anyhow!("Window not found: {}", window_id))?;
179
180 let aggregations = window.aggregation_results()?;
184
185 let result = WindowResult {
186 window_id: window_id.to_string(),
187 window_start: window
188 .config()
189 .window_type
190 .start_time()
191 .unwrap_or(Utc::now()),
192 window_end: Utc::now(),
193 event_count: window.event_count(),
194 aggregations,
195 trigger_reason: "Window trigger condition met".to_string(),
196 processing_time: Utc::now(),
197 };
198
199 self.stats.windows_triggered += 1;
200 info!("Triggered window: {}", window_id);
201
202 Ok(result)
203 }
204
205 fn update_watermark(&mut self, event: &StreamEvent) -> Result<()> {
207 let event_time = event.timestamp();
208 self.watermark_manager.update(event_time);
209 self.watermark = self.watermark_manager.current();
210 Ok(())
211 }
212
213 fn is_late_event(&self, event: &StreamEvent) -> bool {
215 let event_time = event.timestamp();
216 let allowed_lateness = self.watermark_manager.allowed_lateness;
217 event_time < self.watermark - allowed_lateness
218 }
219
220 fn handle_late_event(&mut self, event: StreamEvent) -> Result<()> {
222 if self.late_events.len() >= self.config.max_late_events {
223 self.late_events.pop_front();
224 self.stats.dropped_events += 1;
225 }
226
227 self.late_events.push_back((event, Utc::now()));
228 self.stats.late_events += 1;
229
230 Ok(())
231 }
232
233 fn remove_oldest_window(&mut self) {
235 if let Some((oldest_id, _)) = self.windows.iter().min_by_key(|(_, window)| {
236 window
237 .config()
238 .window_type
239 .start_time()
240 .unwrap_or(Utc::now())
241 }) {
242 let oldest_id = oldest_id.clone();
243 self.windows.remove(&oldest_id);
244 debug!("Removed oldest window: {}", oldest_id);
245 }
246 }
247
248 fn estimate_memory_usage(&self) -> usize {
250 let window_size = std::mem::size_of::<EventWindow>();
252 let late_event_size = std::mem::size_of::<(StreamEvent, DateTime<Utc>)>();
253
254 self.windows.len() * window_size + self.late_events.len() * late_event_size
255 }
256
257 fn update_stats(&mut self, start_time: std::time::Instant) {
259 self.stats.events_processed += 1;
260 self.stats.last_processing_time = Utc::now();
261
262 let elapsed = start_time.elapsed();
263 let latency_ms = elapsed.as_secs_f64() * 1000.0;
264
265 let alpha = 0.1;
267 self.stats.avg_latency_ms = alpha * latency_ms + (1.0 - alpha) * self.stats.avg_latency_ms;
268
269 let current_memory = self.estimate_memory_usage();
271 if current_memory > self.stats.peak_memory_usage {
272 self.stats.peak_memory_usage = current_memory;
273 }
274 }
275
276 pub fn stats(&self) -> &ProcessorStats {
278 &self.stats
279 }
280
281 pub fn active_windows(&self) -> Vec<String> {
283 self.windows.keys().cloned().collect()
284 }
285
286 pub fn get_window(&self, window_id: &str) -> Option<&EventWindow> {
288 self.windows.get(window_id)
289 }
290
291 pub fn remove_window(&mut self, window_id: &str) -> Result<()> {
293 if self.windows.remove(window_id).is_some() {
294 info!("Removed window: {}", window_id);
295 Ok(())
296 } else {
297 Err(anyhow!("Window not found: {}", window_id))
298 }
299 }
300
301 pub fn clear_windows(&mut self) {
303 self.windows.clear();
304 info!("Cleared all windows");
305 }
306
307 pub fn current_watermark(&self) -> DateTime<Utc> {
309 self.watermark
310 }
311
312 pub fn late_events(&self) -> &VecDeque<(StreamEvent, DateTime<Utc>)> {
314 &self.late_events
315 }
316}
317
318impl Default for EventProcessor {
319 fn default() -> Self {
320 Self::new(ProcessorConfig::default())
321 }
322}
323
324trait WindowTypeExt {
326 fn start_time(&self) -> Option<DateTime<Utc>>;
327}
328
329impl WindowTypeExt for super::window::WindowType {
330 fn start_time(&self) -> Option<DateTime<Utc>> {
331 Some(Utc::now())
333 }
334}