mirror of
https://relay.ngit.dev/npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr/ngit-grasp.git
synced 2026-10-05 23:18:24 +00:00
add background job to clean up grasp-audit test events and git repos
Spawns a tokio task that runs every 30 minutes and removes all events tagged 'grasp-audit-test-event' older than 2 hours from the LMDB database, along with their associated bare git repositories on disk.
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
//! Audit Event Cleanup
|
||||
//!
|
||||
//! Background job that periodically removes grasp-audit test events and their
|
||||
//! associated git repositories from the relay.
|
||||
//!
|
||||
//! The grasp-audit tool tags every event it creates with:
|
||||
//! `["t", "grasp-audit-test-event"]`
|
||||
//!
|
||||
//! This job:
|
||||
//! 1. Queries kind 30617 (repo announcement) events tagged "grasp-audit-test-event"
|
||||
//! that are older than `AUDIT_CLEANUP_AGE_SECS` seconds.
|
||||
//! 2. Deletes the corresponding bare git repositories from disk.
|
||||
//! 3. Deletes all events tagged "grasp-audit-test-event" older than the threshold
|
||||
//! from the Nostr database.
|
||||
//!
|
||||
//! Runs every `AUDIT_CLEANUP_INTERVAL_SECS` seconds.
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::time::Duration;
|
||||
|
||||
use nostr_sdk::prelude::*;
|
||||
use tracing::{debug, error, info, warn};
|
||||
|
||||
use crate::nostr::builder::SharedDatabase;
|
||||
use crate::nostr::events::RepositoryAnnouncement;
|
||||
|
||||
/// How old an audit event must be before it is eligible for deletion (2 hours).
|
||||
const AUDIT_CLEANUP_AGE_SECS: u64 = 2 * 3600;
|
||||
|
||||
/// How often the cleanup job runs (30 minutes).
|
||||
const AUDIT_CLEANUP_INTERVAL_SECS: u64 = 30 * 60;
|
||||
|
||||
/// The hashtag used by grasp-audit to mark all test events.
|
||||
const AUDIT_TEST_EVENT_TAG: &str = "grasp-audit-test-event";
|
||||
|
||||
/// Run the audit cleanup loop indefinitely.
|
||||
///
|
||||
/// Spawned as a background tokio task in `main.rs`.
|
||||
pub async fn run_audit_cleanup_loop(database: SharedDatabase, git_data_path: PathBuf) {
|
||||
// Use an interval that fires immediately on the first tick, then every 30 minutes.
|
||||
let mut interval = tokio::time::interval(Duration::from_secs(AUDIT_CLEANUP_INTERVAL_SECS));
|
||||
loop {
|
||||
interval.tick().await;
|
||||
run_audit_cleanup_once(&database, &git_data_path).await;
|
||||
}
|
||||
}
|
||||
|
||||
/// Perform a single cleanup pass.
|
||||
async fn run_audit_cleanup_once(database: &SharedDatabase, git_data_path: &PathBuf) {
|
||||
let cutoff = Timestamp::from(Timestamp::now().as_secs().saturating_sub(AUDIT_CLEANUP_AGE_SECS));
|
||||
|
||||
// --- Step 1: Find repo announcements to delete git repos for ---
|
||||
let repo_filter = Filter::new()
|
||||
.kind(Kind::GitRepoAnnouncement)
|
||||
.hashtag(AUDIT_TEST_EVENT_TAG)
|
||||
.until(cutoff);
|
||||
|
||||
let repo_events = match database.query(repo_filter).await {
|
||||
Ok(events) => events,
|
||||
Err(e) => {
|
||||
error!("audit_cleanup: failed to query repo announcements: {}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let mut repos_deleted = 0usize;
|
||||
let mut repos_failed = 0usize;
|
||||
|
||||
for event in repo_events.iter() {
|
||||
match RepositoryAnnouncement::from_event(event.clone()) {
|
||||
Ok(announcement) => {
|
||||
let repo_path = git_data_path.join(announcement.repo_path());
|
||||
if repo_path.exists() {
|
||||
match std::fs::remove_dir_all(&repo_path) {
|
||||
Ok(()) => {
|
||||
debug!(
|
||||
"audit_cleanup: deleted git repo {}",
|
||||
repo_path.display()
|
||||
);
|
||||
repos_deleted += 1;
|
||||
|
||||
// Remove the parent npub directory if it is now empty
|
||||
if let Some(npub_dir) = repo_path.parent() {
|
||||
if npub_dir.exists() {
|
||||
match std::fs::read_dir(npub_dir) {
|
||||
Ok(mut entries) => {
|
||||
if entries.next().is_none() {
|
||||
if let Err(e) = std::fs::remove_dir(npub_dir) {
|
||||
warn!(
|
||||
"audit_cleanup: could not remove empty npub dir {}: {}",
|
||||
npub_dir.display(),
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
warn!(
|
||||
"audit_cleanup: could not read npub dir {}: {}",
|
||||
npub_dir.display(),
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
warn!(
|
||||
"audit_cleanup: failed to delete git repo {}: {}",
|
||||
repo_path.display(),
|
||||
e
|
||||
);
|
||||
repos_failed += 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
debug!(
|
||||
"audit_cleanup: git repo already absent: {}",
|
||||
repo_path.display()
|
||||
);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
warn!(
|
||||
"audit_cleanup: could not parse repo announcement {}: {}",
|
||||
event.id, e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- Step 2: Delete all audit events from the database ---
|
||||
let all_audit_filter = Filter::new()
|
||||
.hashtag(AUDIT_TEST_EVENT_TAG)
|
||||
.until(cutoff);
|
||||
|
||||
match database.delete(all_audit_filter).await {
|
||||
Ok(()) => {
|
||||
info!(
|
||||
"audit_cleanup: deleted audit events older than {}s; git repos deleted={}, failed={}",
|
||||
AUDIT_CLEANUP_AGE_SECS, repos_deleted, repos_failed
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
error!("audit_cleanup: failed to delete audit events from database: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod audit_cleanup;
|
||||
pub mod config;
|
||||
pub mod git;
|
||||
pub mod http;
|
||||
|
||||
@@ -7,6 +7,7 @@ use tracing::{error, info, warn};
|
||||
use tracing_subscriber::{EnvFilter, FmtSubscriber};
|
||||
|
||||
use ngit_grasp::{
|
||||
audit_cleanup,
|
||||
config::{Config, DatabaseBackend},
|
||||
git, http,
|
||||
metrics::Metrics,
|
||||
@@ -175,6 +176,14 @@ async fn main() -> Result<()> {
|
||||
});
|
||||
info!("Expired event cleanup task started (24h interval, keeps 7 days)");
|
||||
|
||||
// Spawn audit event cleanup task (30m interval, removes events >2h old)
|
||||
let audit_db = relay_with_db.database.clone();
|
||||
let audit_git_path = PathBuf::from(config.effective_git_data_path());
|
||||
tokio::spawn(async move {
|
||||
audit_cleanup::run_audit_cleanup_loop(audit_db, audit_git_path).await;
|
||||
});
|
||||
info!("Audit event cleanup task started (30m interval, removes events >2h old)");
|
||||
|
||||
// Start purgatory sync loop for background git data fetching
|
||||
// Create naughty list tracker for git remote domains with persistent errors (12h expiration)
|
||||
let git_naughty_list = Arc::new(NaughtyListTracker::with_defaults());
|
||||
|
||||
Reference in New Issue
Block a user