main
tag: launch-2026-06-01
tag: magicmirror-v0.1.1
tag: magicmirror-v0.3.0
tag: mnw-cli-v0.1.2
tag: mnw-cli-v0.1.3
tag: mnw-cli-v0.1.4
tag: pom-v0.4.1
tag: pom-v0.4.2
tag: pom-v0.4.3
tag: pom-v0.4.4
tag: pom-v0.4.5
tag: wam-v0.3.0
tag: wam-v0.3.1
Files
Commits
Tags
Notes
Issues
Prune processed-webhook dedup markers (bounded growth)
processed_webhook_events gained one row per Stripe event and was never
pruned — the daily scheduler prunes its siblings but not this table, so
it grew for the life of the deployment (Run #21 Performance SERIOUS).
Add prune_processed_events and run it daily at 30 days, the retention the
table was created with (migration 065); Stripe won't redeliver events that
old, so the dedup guarantee is unaffected.
Co-Authored-By
Claude Opus 4.8 <noreply@anthropic.com>
2 files changed,
+29 insertions,
-0 deletions
57
57
Ok(())
58
58
}
59
59
60
+
/// Delete processed-event dedup markers older than `days`. These markers only
61
+
/// guard against Stripe *redelivering* an event, which it stops doing within a
62
+
/// few days; 30 days is the retention the table was created with (migration
63
+
/// 065) but never enforced — without this prune the table grows one row per
64
+
/// webhook for the life of the deployment (Run #21 Performance SERIOUS).
65
+
#[tracing::instrument(skip_all)]
66
+
pub async fn prune_processed_events(pool: &PgPool, days: i64) -> Result<u64> {
67
+
let result = sqlx::query(
68
+
"DELETE FROM processed_webhook_events \
69
+
WHERE processed_at < NOW() - make_interval(days => $1::int)",
70
+
)
71
+
.bind(days as i32)
72
+
.execute(pool)
73
+
.await?;
74
+
75
+
Ok(result.rows_affected())
76
+
}
77
+
60
78
/// Insert a failed webhook event for later retry.
61
79
#[tracing::instrument(skip_all)]
62
80
pub async fn insert_failed_event(
286
286
}
287
287
Err(e) => tracing::error!(error = ?e, "failed to prune page views"),
288
288
}
289
+
290
+
// Prune processed-webhook dedup markers older than 30 days. Stripe
291
+
// won't redeliver events that old, so they no longer prevent a
292
+
// duplicate; the table is otherwise append-only and grows one row
293
+
// per webhook forever (Run #21 Performance SERIOUS).
294
+
match db::webhook_events::prune_processed_events(&state.db, 30).await {
295
+
Ok(n) => {
296
+
if n > 0 { tracing::info!(pruned = n, "pruned old processed-webhook markers"); }
297
+
}
298
+
Err(e) => tracing::error!(error = ?e, "failed to prune processed-webhook markers"),
299
+
}
289
300
}
290
301
291
302
// Explicitly release the advisory lock (defense-in-depth: also released