diff options
Diffstat (limited to 'makima/src/server/mod.rs')
| -rw-r--r-- | makima/src/server/mod.rs | 61 |
1 files changed, 58 insertions, 3 deletions
diff --git a/makima/src/server/mod.rs b/makima/src/server/mod.rs index 7e31285..256082d 100644 --- a/makima/src/server/mod.rs +++ b/makima/src/server/mod.rs @@ -67,6 +67,7 @@ pub fn make_router(state: SharedState) -> Router { "/mesh/tasks", get(mesh::list_tasks).post(mesh::create_task), ) + .route("/mesh/tasks/anonymous", get(mesh::list_anonymous_tasks)) .route( "/mesh/tasks/{id}", get(mesh::get_task) @@ -241,13 +242,18 @@ const DAEMON_CLEANUP_INTERVAL_SECS: u64 = 60; /// Daemon heartbeat timeout in seconds (delete daemons older than this) const DAEMON_HEARTBEAT_TIMEOUT_SECS: i64 = 120; +/// Anonymous task cleanup interval in hours (check every 24 hours) +const ANONYMOUS_TASK_CLEANUP_INTERVAL_HOURS: u64 = 24; +/// Anonymous task age threshold in days (clean up tasks older than this) +const ANONYMOUS_TASK_MAX_AGE_DAYS: i32 = 7; + /// Run the HTTP server with graceful shutdown support. /// /// # Arguments /// * `state` - Shared application state containing ML models /// * `addr` - Address to bind to (e.g., "0.0.0.0:8080") pub async fn run_server(state: SharedState, addr: &str) -> anyhow::Result<()> { - // Start background daemon cleanup task if database is available + // Start background cleanup tasks if database is available if let Some(pool) = state.db_pool.clone() { // Initial cleanup of any stale daemons from previous server run match crate::db::repository::delete_stale_daemons(&pool, 0).await { @@ -263,7 +269,8 @@ pub async fn run_server(state: SharedState, addr: &str) -> anyhow::Result<()> { _ => {} } - // Spawn periodic cleanup task + // Spawn periodic daemon cleanup task + let daemon_pool = pool.clone(); tokio::spawn(async move { let mut interval = tokio::time::interval( std::time::Duration::from_secs(DAEMON_CLEANUP_INTERVAL_SECS) @@ -271,7 +278,7 @@ pub async fn run_server(state: SharedState, addr: &str) -> anyhow::Result<()> { loop { interval.tick().await; match crate::db::repository::delete_stale_daemons( - &pool, + &daemon_pool, DAEMON_HEARTBEAT_TIMEOUT_SECS, ).await { Ok(deleted) if deleted > 0 => { @@ -288,6 +295,54 @@ pub async fn run_server(state: SharedState, addr: &str) -> anyhow::Result<()> { } } }); + + // Spawn periodic anonymous task cleanup job + let task_pool = pool.clone(); + tokio::spawn(async move { + let mut interval = tokio::time::interval( + std::time::Duration::from_secs(ANONYMOUS_TASK_CLEANUP_INTERVAL_HOURS * 3600) + ); + loop { + interval.tick().await; + match crate::db::repository::get_stale_anonymous_tasks( + &task_pool, + ANONYMOUS_TASK_MAX_AGE_DAYS, + ).await { + Ok(tasks) => { + if !tasks.is_empty() { + tracing::info!( + count = tasks.len(), + max_age_days = ANONYMOUS_TASK_MAX_AGE_DAYS, + "Starting cleanup of stale anonymous tasks" + ); + } + for task in tasks { + tracing::info!( + task_id = %task.id, + task_name = %task.name, + "Cleaning up stale anonymous task" + ); + + // TODO: Also clean up worktree if it exists on daemon + // For now, we just delete the database records + if let Err(e) = crate::db::repository::delete_task_cascade( + &task_pool, + task.id, + ).await { + tracing::error!( + task_id = %task.id, + error = %e, + "Failed to delete anonymous task" + ); + } + } + } + Err(e) => { + tracing::error!(error = %e, "Failed to query stale anonymous tasks"); + } + } + } + }); } let app = make_router(state); |
