package main import ( "context" "log/slog" "time" "github.com/noderunners/nip05api/internal/db" ) // cleanupWorker prunes old delivered/dead outbox rows hourly so the DB stays // small. Delivered: 7 days. Dead: 30 days (kept longer for forensic value). type cleanupWorker struct { db *db.DB } func newCleanupWorker(d *db.DB) *cleanupWorker { return &cleanupWorker{db: d} } func (c *cleanupWorker) Run(ctx context.Context) { t := time.NewTicker(1 * time.Hour) defer t.Stop() for { select { case <-ctx.Done(): return case <-t.C: c.prune(ctx) } } } func (c *cleanupWorker) prune(ctx context.Context) { queries := []struct { label string query string args []any }{ {"webhook delivered", `DELETE FROM webhook_outbox WHERE status = 'delivered' AND created_at < ?`, []any{time.Now().UTC().Add(-7 * 24 * time.Hour).Format(time.RFC3339)}}, {"webhook dead", `DELETE FROM webhook_outbox WHERE status = 'dead' AND created_at < ?`, []any{time.Now().UTC().Add(-30 * 24 * time.Hour).Format(time.RFC3339)}}, {"dm delivered", `DELETE FROM dm_outbox WHERE status = 'delivered' AND created_at < ?`, []any{time.Now().UTC().Add(-7 * 24 * time.Hour).Format(time.RFC3339)}}, {"dm dead", `DELETE FROM dm_outbox WHERE status = 'dead' AND created_at < ?`, []any{time.Now().UTC().Add(-30 * 24 * time.Hour).Format(time.RFC3339)}}, {"audit", `DELETE FROM audit_log WHERE created_at < ?`, []any{time.Now().UTC().Add(-180 * 24 * time.Hour).Format(time.RFC3339)}}, } for _, q := range queries { res, err := c.db.ExecContext(ctx, q.query, q.args...) if err != nil { slog.Warn("cleanup", "label", q.label, "err", err) continue } if n, _ := res.RowsAffected(); n > 0 { slog.Info("cleanup", "label", q.label, "rows", n) } } }