max / makenotwork
1 file changed,
+10 insertions,
-0 deletions
| @@ -88,6 +88,16 @@ pub(super) async fn webhook_v2( | |||
| 88 | 88 | // scheduler), matching v1's failure path rather than relying solely on | |
| 89 | 89 | // Stripe's redelivery window. Not marked processed, so a Stripe | |
| 90 | 90 | // redelivery also still re-runs the idempotent handler. | |
| 91 | + | // | |
| 92 | + | // Deliberate trade (fuzz 2026-07-06, Payments): returning 200 below ACKs | |
| 93 | + | // the event to Stripe, so Stripe will not redeliver it on its own 3-day | |
| 94 | + | // schedule — the in-house queue + scheduler owns retry from here (richer: | |
| 95 | + | // local backoff + dead-lettering). The operational consequence is that | |
| 96 | + | // for a persistently-failing money event, **scheduler liveness is the | |
| 97 | + | // only retry backstop**; if the scheduler is down, a failed webhook has no | |
| 98 | + | // external redelivery. The `insert_failed_event` guard below returns 503 | |
| 99 | + | // (inviting Stripe redelivery) if even the queue insert fails, so the net | |
| 100 | + | // is never "silently dropped". | |
| 91 | 101 | tracing::warn!(event_id = %thin.id, error = ?e, "v2 event processing failed; queueing for retry"); | |
| 92 | 102 | if let Err(queue_err) = db::webhook_events::insert_failed_event( | |
| 93 | 103 | &state.db, |