mockforge_analytics/
retention.rs1use crate::config::RetentionConfig;
4use crate::database::AnalyticsDatabase;
5use crate::error::Result;
6use std::sync::Arc;
7use tokio::time::{interval, Duration};
8use tracing::{error, info};
9
10pub struct RetentionService {
12 db: AnalyticsDatabase,
13 config: RetentionConfig,
14}
15
16impl RetentionService {
17 pub fn new(db: AnalyticsDatabase, config: RetentionConfig) -> Self {
19 Self { db, config }
20 }
21
22 pub async fn start(self: Arc<Self>) {
24 info!("Starting data retention service");
25
26 let interval_seconds = self.config.cleanup_interval_hours as u64 * 3600;
27 let mut interval = interval(Duration::from_secs(interval_seconds));
28
29 loop {
30 interval.tick().await;
31
32 if let Err(e) = self.run_cleanup().await {
33 error!("Error running data cleanup: {}", e);
34 }
35 }
36 }
37
38 async fn run_cleanup(&self) -> Result<()> {
40 info!("Running analytics data cleanup");
41
42 let deleted = self.db.cleanup_minute_aggregates(self.config.minute_aggregates_days).await?;
44 info!("Deleted {} old minute aggregates", deleted);
45
46 let deleted = self.db.cleanup_hour_aggregates(self.config.hour_aggregates_days).await?;
48 info!("Deleted {} old hour aggregates", deleted);
49
50 let deleted = self.db.cleanup_error_events(self.config.error_events_days).await?;
52 info!("Deleted {} old error events", deleted);
53
54 self.db.vacuum().await?;
56
57 info!("Data cleanup completed successfully");
58 Ok(())
59 }
60
61 pub async fn trigger_cleanup(&self) -> Result<()> {
63 self.run_cleanup().await
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70 use std::path::Path;
71
72 #[tokio::test]
73 async fn test_retention_service_creation() {
74 let db = AnalyticsDatabase::new(Path::new(":memory:")).await.unwrap();
75 db.run_migrations().await.unwrap();
76
77 let config = RetentionConfig::default();
78 let service = RetentionService::new(db, config);
79
80 service.trigger_cleanup().await.unwrap();
82 }
83}