stripe / stripe-cli

A command-line tool for Stripe
https://stripe.com/docs/stripe-cli
Apache License 2.0
1.59k stars 372 forks source link

Support webhook retries with Stripe CLI #313

Open sedubois opened 4 years ago

sedubois commented 4 years ago

Problem

When creating webhook endpoints, webhooks which fail to get delivered (get a 4xx/5xx error code) are automatically retried, and it is also possible to see in the dashboard a log of all sent webhooks and whether they succeeded.

However no such option appears to be available when receiving webhooks through the CLI: failed deliveries are not retried, and no log are provided in the dashboard.

2019-11-14 09:05:09   --> customer.subscription.updated [evt_1FedKBFmaCD2jpsQmtIyilyD]
2019-11-14 09:05:09  <--  [404] POST http://localhost:3000/api/v1/stripe/webhook [evt_1FedKBFmaCD2jpsQmtIyilyD]
...
// evt_1FedKBFmaCD2jpsQmtIyilyD does not get re-sent

I have been looking for a retry mechanism because there can be a race condition between the reception of the stripe.subscription.created and subsequent events such as customer.updated and stripe.subscription.updated (this actually appears to be systematic when running on my machine).

I am aware that the Stripe docs explicitly warn against relying on events being received in any specific order, but nevertheless I think there would be value in having the same behaviour with Stripe CLI as with endpoints.

Feature

Support same features with webhooks sent to Stripe CLI as those sent to webhook endpoints:

tomer-stripe commented 4 years ago

This is an interesting idea! Wonder if we could add this as an optional feature 🤔

If you're developing locally and hit a 404 it seems like retrying immediately would not be too useful since it would require changing something on the server-side to resolve that.

@ob-stripe what do you think?

tomer-stripe commented 4 years ago

@sedubois also if you go to the dashboard page for the event itself you should see CLI responses there (evt_1FedKBFmaCD2jpsQmtIyilyD)

KamilKopaczyk commented 4 years ago

Not sure since when this is available, but you can call stripe events resend evt_<event ID> from CLI (be sure that stripe-cli is listening though).

It worked for me even when my stripe-cli instance was not registered as webhook endpoint at the time of event being created.

jonbarrow commented 2 years ago

Old issue but I have the same problem. My application implements self recovery by checking for any unsuccessful webhooks at boot and then handling them. When using the Stripe CLI none of the events are marked as unsuccessful even when the server is not running, making it impossible to test this self recovery without being deployed live

gregveres commented 1 year ago

I ran across the need for this today. The issue I am running into is that the stripe cli is sending the webhook too quickly. The operation that created the payment is still saving everything to the database when it gets interupted to handle the webhook. In the handler I go looking for the db entry and it isn't there. I send a failure back to stripe to indicate that I need the webhook to be retried.

It would be great if the stripe cli had a way to retry the webhook after 5 to 10 seconds or so, maybe with a backoff.

I am finding that the local development webhooks are not showing up in the dashboard so I can't retry them there. And if I did retry them, it would send them to my test server, not back to the stripe cli.

glspdotnet commented 1 year ago

Hey, @gregveres! As @KamilKopaczyk mentioned, you might want to check out stripe events resend --help if you haven't already. You can replay events and have them sent to specific endpoints using --webhook-endpoint (for webooks) or --device-name (for a local/CLI device).

As for the async ("Stripe is too fast!" 😄) webhook issue, here are some example solutions from Laravel's Cashier package:

https://github.com/laravel/cashier-stripe/pull/1227 https://github.com/laravel/cashier-stripe/pull/1243

I'm personally using the admittedly-ugly introduction of a one second delay in my own site without any issue. This allows for enough time for models related to my Stripe subscriptions (items, delivery addresses, etc.) to be created. My webhooks are handled in a background queue anyways, so there's no noticeable delay for the end user.

gregveres commented 1 year ago

@glspdotnet wouldn't a better approach be to just return an error to stripe's webhook so that stripe takes care of backing off and retrying? For instance, if the update event arrives and you have no db entry that corresponds to the session, just return a 404. Stripe will then retry the webhook after some time, Then, presumably, your code would have handled the create webhook that would create the db entries. Stripe then retries the update event and this time the db entries are there. If they aren't there yet, then stripe backs off again, this time with a longer delay.

I used to get db collisions because I create most of my db entries before I make the call to stripe. Each of my db entries have a Sql Server Timestamp field so Sql Server can detect a collision. Stripe would blast my system with the webhooks, all at once. I originally coded my webhooks to retry the update in a loop until some number of retries failed or it was successful. Then I realized this was more complexity than I needed. I just needed to tell stripe that the webhook failed and let it do the back off and retry for me.

Chi8wah commented 1 month ago

It seems this problem is still not resolved today. I was going to test if my code could handle the missing delivery event of subscription cycle on my local computer through stripe CLI, but soon I found that stripe will only mark the event as failed/pending when it‘s sended to the webhook endpoint. Even though I response an error code through stripe CLI, the status of the event is still Delivered.