Skip to main content

systemprompt_users/jobs/
cleanup_anonymous_users.rs

1use anyhow::Result;
2use async_trait::async_trait;
3use std::sync::Arc;
4use systemprompt_database::DbPool;
5use systemprompt_traits::{Job, JobContext, JobResult};
6use tracing::info;
7
8use crate::UserService;
9
10const ANONYMOUS_USER_RETENTION_DAYS: i32 = 30;
11
12#[derive(Debug, Clone, Copy)]
13pub struct CleanupAnonymousUsersJob;
14
15#[async_trait]
16impl Job for CleanupAnonymousUsersJob {
17    fn name(&self) -> &'static str {
18        "cleanup_anonymous_users"
19    }
20
21    fn description(&self) -> &'static str {
22        "Cleans up old anonymous users (30d)"
23    }
24
25    fn schedule(&self) -> &'static str {
26        "0 0 * * * *"
27    }
28
29    async fn execute(&self, ctx: &JobContext) -> Result<JobResult> {
30        let start_time = std::time::Instant::now();
31
32        let db_pool = Arc::clone(
33            ctx.db_pool::<DbPool>()
34                .ok_or_else(|| anyhow::anyhow!("DbPool not available in job context"))?,
35        );
36
37        info!("Job started");
38
39        let user_service = UserService::new(&db_pool)?;
40        let deleted_users = user_service
41            .cleanup_old_anonymous(ANONYMOUS_USER_RETENTION_DAYS)
42            .await?;
43
44        let duration_ms = start_time.elapsed().as_millis() as u64;
45
46        info!(
47            deleted_users = deleted_users,
48            duration_ms = duration_ms,
49            "Job completed"
50        );
51
52        Ok(JobResult::success()
53            .with_stats(deleted_users, 0)
54            .with_duration(duration_ms))
55    }
56}
57
58systemprompt_provider_contracts::submit_job!(&CleanupAnonymousUsersJob);