use std::time::Duration; use export::AppState; use models::users::user_recent_mentions; use sea_orm::{ColumnTrait, EntityTrait, QueryFilter}; use time::OffsetDateTime; use crate::errors::ChatError; use crate::services::service::ChatService; pub(crate) const STUCK_CLAIM_MINUTES: i64 = 10; const MENTION_RETENTION_DAYS: i64 = 90; impl ChatService { pub async fn prune_old_mentions(&self) -> Result<(), ChatError> { let cutoff = OffsetDateTime::now_utc() - time::Duration::days(MENTION_RETENTION_DAYS); user_recent_mentions::Entity::delete_many() .filter(user_recent_mentions::Column::CreatedAt.lt(cutoff)) .exec(self.db().write()) .await?; Ok(()) } } pub async fn run_background_tasks(state: AppState) { let service = ChatService::new(state); let mut interval = tokio::time::interval(Duration::from_secs(30)); interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay); let mut tick: u32 = 0; loop { interval.tick().await; if let Err(error) = service.deliver_due_reminders().await { tracing::warn!(%error, "chat reminder delivery failed"); } if let Err(error) = service.deliver_pending_webhook_events().await { tracing::warn!(%error, "chat outbound webhook delivery failed"); } tick = tick.wrapping_add(1); if tick.is_multiple_of(120) { if let Err(error) = service.prune_old_mentions().await { tracing::warn!(%error, "chat mention prune failed"); } if let Err(error) = service.cleanup_stale_attachments().await { tracing::warn!(%error, "chat attachment cleanup failed"); } } } }