docbox_core/files/
purge_expired_presigned_tasks.rs

1use crate::{
2    secrets::AppSecretManager,
3    storage::{StorageLayerFactory, TenantStorageLayer},
4};
5use chrono::Utc;
6use docbox_database::{
7    DatabasePoolCache, DbPool,
8    models::{
9        presigned_upload_task::{PresignedTaskStatus, PresignedUploadTask},
10        tenant::Tenant,
11    },
12};
13use std::sync::Arc;
14
15pub async fn safe_purge_expired_presigned_tasks(
16    db_cache: Arc<DatabasePoolCache<AppSecretManager>>,
17    storage: StorageLayerFactory,
18) {
19    if let Err(cause) = purge_expired_presigned_tasks(db_cache, storage).await {
20        tracing::error!(?cause, "failed to purge presigned tasks");
21    }
22}
23
24pub async fn purge_expired_presigned_tasks(
25    db_cache: Arc<DatabasePoolCache<AppSecretManager>>,
26    storage: StorageLayerFactory,
27) -> anyhow::Result<()> {
28    let db = db_cache.get_root_pool().await?;
29    let tenants = Tenant::all(&db).await?;
30    drop(db);
31
32    for tenant in tenants {
33        // Create the database connection pool
34        let db = db_cache.get_tenant_pool(&tenant).await?;
35        let storage = storage.create_storage_layer(&tenant);
36
37        if let Err(cause) = purge_expired_presigned_tasks_tenant(&db, &storage).await {
38            tracing::error!(
39                ?cause,
40                ?tenant,
41                "failed to purge presigned tasks for tenant"
42            );
43        }
44    }
45
46    Ok(())
47}
48
49pub async fn purge_expired_presigned_tasks_tenant(
50    db: &DbPool,
51    storage: &TenantStorageLayer,
52) -> anyhow::Result<()> {
53    let current_date = Utc::now();
54    let tasks = PresignedUploadTask::find_expired(db, current_date).await?;
55    if tasks.is_empty() {
56        return Ok(());
57    }
58
59    for task in tasks {
60        // Delete the task itself
61        if let Err(cause) = PresignedUploadTask::delete(db, task.id).await {
62            tracing::error!(?cause, "failed to delete presigned upload task")
63        }
64
65        // Delete incomplete file uploads
66        match task.status {
67            PresignedTaskStatus::Completed { .. } => {
68                // Upload completed, nothing to revert
69            }
70            PresignedTaskStatus::Failed { .. } | PresignedTaskStatus::Pending => {
71                if let Err(cause) = storage.delete_file(&task.file_key).await {
72                    tracing::error!(
73                        ?cause,
74                        "failed to delete expired presigned task file from tenant"
75                    );
76                }
77            }
78        }
79    }
80
81    Ok(())
82}