Michael Chihlas
06200fabb1
fix(billing): make Stripe webhook idempotency atomic so failed handlers can retry
...
Previously `apply_subscription_event` committed the StripeEvent idempotency
row before invoking the handler, then the handlers each committed their own
mutations. If a handler raised mid-flight (transient DB error, network blip,
race), the idempotency mark was already persisted — Stripe's retry would hit
the IntegrityError branch and silently return False, and the subscription
state would permanently desync from Stripe.
Switch to a single atomic transaction:
- Insert the StripeEvent + flush (catch IntegrityError on duplicate event_id).
- Run the handler.
- Commit on success; roll back the entire transaction on failure and re-raise.
Drop the four `db.commit()` calls inside `_handle_*` so the outer caller owns
commit. The webhook endpoint already lets exceptions propagate, so a 500
response now correctly tells Stripe to retry.
Tests: three new regression cases in test_stripe_webhook_handler.py covering
handler failure (no idempotency mark persisted), retry-after-failure success,
and duplicate-event-id skip.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-05-07 01:36:13 -04:00
..
2026-05-06 19:14:30 -04:00
2026-05-06 19:14:30 -04:00
2026-05-06 21:34:22 -04:00
2026-05-06 19:14:30 -04:00
2026-03-04 20:44:25 -05:00
2026-05-06 19:14:30 -04:00
2026-03-04 20:44:25 -05:00
2026-02-08 06:05:59 -05:00
2026-04-12 03:48:30 +00:00
2026-02-08 06:05:59 -05:00
2026-02-08 06:05:59 -05:00
2026-04-11 04:24:36 +00:00
2026-05-06 20:35:10 -04:00
2026-02-08 06:05:59 -05:00
2026-04-13 04:44:51 -04:00
2026-03-01 14:21:48 -05:00
2026-03-07 15:51:37 -05:00
2026-04-25 06:13:23 -04:00
2026-02-26 17:25:38 -05:00
2026-02-26 17:25:34 -05:00
2026-02-27 00:08:20 -05:00
2026-03-07 15:51:37 -05:00
2026-02-28 19:18:02 -05:00
2026-04-11 04:24:36 +00:00
2026-02-16 15:23:14 -05:00
2026-03-04 20:44:25 -05:00
2026-02-07 02:39:01 -05:00
2026-02-17 12:29:04 -05:00
2026-05-06 23:43:35 -04:00
2026-05-06 19:14:30 -04:00
2026-05-06 20:00:08 -04:00
2026-05-06 19:14:30 -04:00
2026-05-06 19:14:30 -04:00
2026-03-24 08:36:13 +00:00
2026-04-25 06:13:23 -04:00
2026-04-11 04:24:36 +00:00
2026-03-07 15:51:37 -05:00
2026-05-06 20:38:50 -04:00
2026-04-11 04:24:36 +00:00
2026-05-06 19:14:30 -04:00
2026-05-06 19:14:30 -04:00
2026-03-04 20:44:25 -05:00
2026-04-27 19:47:43 -04:00
2026-02-08 14:53:22 -05:00
2026-02-18 17:56:29 -05:00
2026-04-30 17:32:37 -04:00
2026-04-23 15:08:43 -04:00
2026-04-24 02:34:06 -04:00
2026-04-27 15:25:46 -04:00
2026-05-06 19:14:30 -04:00
2026-04-30 16:21:20 -04:00
2026-02-11 21:42:58 -05:00
2026-05-06 19:14:30 -04:00
2026-04-11 04:24:36 +00:00
2026-02-17 10:54:39 -05:00
2026-04-13 02:38:01 -04:00
2026-05-07 01:30:14 -04:00
2026-05-06 19:14:30 -04:00
2026-05-06 19:14:30 -04:00
2026-05-06 20:04:43 -04:00
2026-05-06 23:19:58 -04:00
2026-03-17 00:28:22 -04:00
2026-04-12 03:48:30 +00:00
2026-02-08 17:58:48 -05:00
2026-04-11 07:02:35 +00:00
2026-04-22 00:15:29 -04:00
2026-04-22 02:37:49 -04:00
2026-05-06 19:14:30 -04:00
2026-05-06 23:26:27 -04:00
2026-03-10 09:49:51 -04:00
2026-04-23 15:17:21 -04:00
2026-03-15 01:45:35 -04:00
2026-03-15 01:45:35 -04:00
2026-02-13 13:12:52 -05:00
2026-04-16 03:01:21 +00:00
2026-04-25 06:13:23 -04:00
2026-04-11 04:24:36 +00:00
2026-02-16 15:23:14 -05:00
2026-02-14 00:11:20 -05:00
2026-04-11 04:24:36 +00:00
2026-04-24 16:09:13 -04:00
2026-05-06 20:12:03 -04:00
2026-04-11 04:24:36 +00:00
2026-04-24 02:24:57 -04:00
2026-04-25 06:13:23 -04:00
2026-03-14 20:18:59 -04:00
2026-04-09 17:18:38 +00:00
2026-04-09 17:18:38 +00:00
2026-03-18 02:38:42 +00:00
2026-04-12 02:44:36 +00:00
2026-04-25 06:13:23 -04:00
2026-04-21 21:13:44 -04:00
2026-04-30 16:21:20 -04:00
2026-04-25 06:13:23 -04:00
2026-04-25 06:13:23 -04:00
2026-04-25 12:01:05 -04:00
2026-03-11 01:59:12 -04:00
2026-02-08 17:58:48 -05:00
2026-03-16 01:35:16 -04:00
2026-02-25 23:17:29 -05:00
2026-05-07 01:36:13 -04:00
2026-05-06 19:14:30 -04:00
2026-05-06 19:14:30 -04:00
2026-05-06 19:14:30 -04:00
2026-03-17 00:22:40 -04:00
2026-03-05 07:55:49 -05:00
2026-04-11 07:02:35 +00:00
2026-04-10 03:50:59 +00:00
2026-05-06 19:14:30 -04:00
2026-02-07 19:10:47 -05:00
2026-02-10 09:45:26 -05:00
2026-04-25 06:13:23 -04:00
2026-03-07 15:51:37 -05:00
2026-02-23 00:03:54 -05:00
2026-04-10 04:17:31 +00:00
2026-04-25 06:13:23 -04:00
2026-05-06 19:14:30 -04:00
2026-02-10 09:45:26 -05:00