systemprompt-scheduler 0.2.4

Background jobs, cron tasks, and job-extension dispatch for systemprompt.io AI governance infrastructure. Tokio-backed scheduling for the MCP governance pipeline.
Documentation
use anyhow::Result;
use async_trait::async_trait;
use systemprompt_database::{CleanupRepository, DbPool};
use systemprompt_traits::{Job, JobContext, JobResult};
use tracing::debug;

#[derive(Debug, Clone, Copy)]
pub struct DatabaseCleanupJob;

#[async_trait]
impl Job for DatabaseCleanupJob {
    fn name(&self) -> &'static str {
        "database_cleanup"
    }

    fn description(&self) -> &'static str {
        "Cleans up orphaned logs, MCP executions, and expired OAuth tokens"
    }

    fn schedule(&self) -> &'static str {
        "0 0 3 * * *"
    }

    async fn execute(&self, ctx: &JobContext) -> Result<JobResult> {
        let start_time = std::time::Instant::now();

        let db_pool = std::sync::Arc::clone(
            ctx.db_pool::<DbPool>()
                .ok_or_else(|| anyhow::anyhow!("DbPool not available in job context"))?,
        );

        debug!("Job started");

        let write_pool = db_pool.write_pool_arc()?;
        let cleanup_repo = CleanupRepository::new_with_write_pool((*write_pool).clone());
        let mut total_deleted = 0u64;

        let orphaned_logs = cleanup_repo.delete_orphaned_logs().await?;
        total_deleted += orphaned_logs;

        let orphaned_mcp = cleanup_repo.delete_orphaned_mcp_executions().await?;
        total_deleted += orphaned_mcp;

        let old_logs = cleanup_repo.delete_old_logs(30).await?;
        total_deleted += old_logs;

        let oauth_codes = cleanup_repo.delete_expired_oauth_codes().await?;
        let oauth_tokens = cleanup_repo.delete_expired_oauth_tokens().await?;
        total_deleted += oauth_codes + oauth_tokens;

        let duration_ms = start_time.elapsed().as_millis() as u64;

        debug!(
            total_deleted = total_deleted,
            orphaned_logs = orphaned_logs,
            orphaned_mcp = orphaned_mcp,
            old_logs = old_logs,
            oauth_codes = oauth_codes,
            oauth_tokens = oauth_tokens,
            duration_ms = duration_ms,
            "Job completed"
        );

        Ok(JobResult::success()
            .with_stats(total_deleted, 0)
            .with_duration(duration_ms))
    }
}

systemprompt_provider_contracts::submit_job!(&DatabaseCleanupJob);