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 #[must_use]
19 pub const fn new(db: AnalyticsDatabase, config: RetentionConfig) -> Self {
20 Self { db, config }
21 }
22
23 pub async fn start(self: Arc<Self>) {
25 info!("Starting data retention service");
26
27 let interval_seconds = u64::from(self.config.cleanup_interval_hours) * 3600;
28 let mut interval = interval(Duration::from_secs(interval_seconds));
29
30 loop {
31 interval.tick().await;
32
33 if let Err(e) = self.run_cleanup().await {
34 error!("Error running data cleanup: {}", e);
35 }
36 }
37 }
38
39 async fn run_cleanup(&self) -> Result<()> {
41 info!("Running analytics data cleanup");
42
43 let deleted = self.db.cleanup_minute_aggregates(self.config.minute_aggregates_days).await?;
45 info!("Deleted {} old minute aggregates", deleted);
46
47 let deleted = self.db.cleanup_hour_aggregates(self.config.hour_aggregates_days).await?;
49 info!("Deleted {} old hour aggregates", deleted);
50
51 let deleted = self.db.cleanup_error_events(self.config.error_events_days).await?;
53 info!("Deleted {} old error events", deleted);
54
55 self.db.vacuum().await?;
57
58 info!("Data cleanup completed successfully");
59 Ok(())
60 }
61
62 pub async fn trigger_cleanup(&self) -> Result<()> {
64 self.run_cleanup().await
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71 use std::path::Path;
72
73 #[tokio::test]
74 async fn test_retention_service_creation() {
75 let db = AnalyticsDatabase::new(Path::new(":memory:")).await.unwrap();
76 db.run_migrations().await.unwrap();
77
78 let config = RetentionConfig::default();
79 let service = RetentionService::new(db, config);
80
81 service.trigger_cleanup().await.unwrap();
83 }
84}