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