feat: add cron-triggered task for purging soft-deleted ciphers

This commit is contained in:
qaz741wsd856 2025-11-28 16:57:46 +00:00
parent ffb8823f4c
commit 3bd68ababf
5 changed files with 153 additions and 1 deletions

View file

@ -104,6 +104,35 @@ There are no immediate plans to implement these features. The primary goal of th
This project requires minimal configuration. The main configuration is done in the `wrangler.toml` file, where you specify your D1 database binding.
### Other Environment Variables
You can configure the following environment variables in `wrangler.toml` under the `[vars]` section, or set them via Cloudflare Dashboard:
* **`TRASH_AUTO_DELETE_DAYS`** (Optional, Default: `30`)
Number of days to keep soft-deleted items before automatically purging them. When a cipher is deleted, it's marked with a `deleted_at` timestamp (soft delete). After the specified number of days, the item will be permanently removed from the database.
* Set to `0` or a negative value to disable automatic purging
* Defaults to `30` days if not specified
* Example: `TRASH_AUTO_DELETE_DAYS = "7"` to keep deleted items for 7 days
* **`IMPORT_BATCH_SIZE`** (Optional, Default: `30`)
Number of records to process in each batch when importing data. This helps manage memory usage and processing time for large imports.
* Set to `0` to disable batching (all records imported in a single batch)
* Defaults to `30` records per batch if not specified
* Example: `IMPORT_BATCH_SIZE = "50"` to process 50 records per batch
### Scheduled Tasks (Cron)
The worker includes a scheduled task that runs automatically to clean up soft-deleted items. By default, this task runs daily at 03:00 UTC.
* **Automatic Cleanup:** The scheduled task automatically purges ciphers that have been soft-deleted for longer than the `TRASH_AUTO_DELETE_DAYS` period
* **Schedule:** Configured in `wrangler.toml` under `[triggers]` section with cron expression `"0 3 * * *"` (daily at 03:00 UTC)
You can modify the cron schedule in `wrangler.toml` if you want to run the cleanup task at a different time or frequency. See [Cloudflare Cron Triggers documentation](https://developers.cloudflare.com/workers/configuration/cron-triggers/) for cron expression syntax.
## Contributing
Contributions are welcome! If you find a bug, have a feature request, or want to improve the code, please open an issue or submit a pull request.

View file

@ -5,3 +5,4 @@ pub mod identity;
pub mod sync;
pub mod folders;
pub mod import;
pub mod purge;

84
src/handlers/purge.rs Normal file
View file

@ -0,0 +1,84 @@
//! Purge handler for cleaning up soft-deleted ciphers
//!
//! This module handles the automatic cleanup of ciphers that have been
//! soft-deleted (marked with deleted_at) for longer than the configured
//! retention period.
use chrono::{Duration, Utc};
use worker::{query, D1Database, Env};
/// Default number of days to keep soft-deleted items before purging
const DEFAULT_PURGE_DAYS: i64 = 30;
/// Get the purge threshold days from environment variable or use default
fn get_purge_days(env: &Env) -> i64 {
env.var("TRASH_AUTO_DELETE_DAYS")
.ok()
.and_then(|v| v.to_string().parse::<i64>().ok())
.unwrap_or(DEFAULT_PURGE_DAYS)
}
/// Purge soft-deleted ciphers that are older than the configured threshold.
///
/// This function:
/// 1. Calculates the cutoff timestamp based on TRASH_AUTO_DELETE_DAYS env var (default: 30 days)
/// 2. Deletes all ciphers where deleted_at is not null and older than the cutoff
/// 3. If TRASH_AUTO_DELETE_DAYS is set to 0 or negative, skips purging (disabled)
///
/// Returns the number of purged records on success.
pub async fn purge_deleted_ciphers(env: &Env) -> Result<u32, worker::Error> {
let purge_days = get_purge_days(env);
// If purge_days is 0 or negative, auto-purge is disabled
if purge_days <= 0 {
log::info!("Auto-purge is disabled (TRASH_AUTO_DELETE_DAYS <= 0)");
return Ok(0);
}
let db: D1Database = env.d1("vault1")?;
// Calculate the cutoff timestamp
let now = Utc::now();
let cutoff = now - Duration::days(purge_days);
let cutoff_str = cutoff.format("%Y-%m-%dT%H:%M:%S%.3fZ").to_string();
log::info!(
"Purging soft-deleted ciphers older than {} days (before {})",
purge_days,
cutoff_str
);
// First, count the records to be deleted (for logging purposes)
let count_result = query!(
&db,
"SELECT COUNT(*) as count FROM ciphers WHERE deleted_at IS NOT NULL AND deleted_at < ?1",
cutoff_str
)?
.first::<CountResult>(None)
.await?;
let count = count_result.map(|r| r.count).unwrap_or(0);
if count > 0 {
// Delete the records
query!(
&db,
"DELETE FROM ciphers WHERE deleted_at IS NOT NULL AND deleted_at < ?1",
cutoff_str
)?
.run()
.await?;
log::info!("Successfully purged {} soft-deleted cipher(s)", count);
} else {
log::info!("No soft-deleted ciphers to purge");
}
Ok(count)
}
/// Helper struct for count query result
#[derive(serde::Deserialize)]
struct CountResult {
count: u32,
}

View file

@ -30,3 +30,26 @@ pub async fn main(
Ok(app.call(req).await?)
}
/// Scheduled event handler for cron-triggered tasks.
///
/// This handler is triggered by Cloudflare's cron triggers configured in wrangler.toml.
/// It performs automatic cleanup of soft-deleted ciphers that have exceeded the
/// retention period (default: 30 days, configurable via TRASH_AUTO_DELETE_DAYS env var).
#[event(scheduled)]
pub async fn scheduled(_event: ScheduledEvent, env: Env, _ctx: ScheduleContext) {
// Set up logging
console_error_panic_hook::set_once();
let _ = console_log::init_with_level(log::Level::Debug);
log::info!("Scheduled task triggered: purging soft-deleted ciphers");
match handlers::purge::purge_deleted_ciphers(&env).await {
Ok(count) => {
log::info!("Scheduled purge completed: {} cipher(s) removed", count);
}
Err(e) => {
log::error!("Scheduled purge failed: {:?}", e);
}
}
}

View file

@ -1,6 +1,7 @@
name = "warden-worker"
main = "build/index.js"
compatibility_date = "2025-09-19"
keep_vars = true
[build]
command = "cargo install -q worker-build && worker-build --release"
@ -8,7 +9,16 @@ command = "cargo install -q worker-build && worker-build --release"
[vars]
# Optional: Set the batch size for imports. Defaults to 30 if not set.
# Set to 0 means no batching (all records imported in a single batch).
# IMPORT_BATCH_SIZE = "30"
# IMPORT_BATCH_SIZE = "30"
# Number of days to keep soft-deleted items before auto-purging.
# Defaults to 30 days if not set. Set to 0 to disable auto-purge.
# TRASH_AUTO_DELETE_DAYS = "30"
# Cron triggers for scheduled tasks
# Runs daily at 03:00 UTC to purge soft-deleted ciphers
[triggers]
crons = ["0 3 * * *"]
[[d1_databases]]
binding = "vault1"
@ -17,6 +27,11 @@ database_id = "${D1_DATABASE_ID}"
[env.dev]
name = "warden-worker-dev"
keep_vars = true
# Dev environment also needs cron triggers
[env.dev.triggers]
crons = ["0 3 * * *"]
[[env.dev.d1_databases]]
binding = "vault1"