Live data from Hacker News

APIs, robustness, and idempotency

stripe.com

21–30 of 52 posts

Re: APIs, robustness, and idempotency

#21

I'm shocked at how few HTTP libraries on GitHub properly handle exponential backoff, let alone retries. Do the Internet a favor, and file an issue with your favorite HTTP library asking them to implement exponential backoff. I haven't found anything in JS that does this properly though. Do people really just write apps that crap out upon the first HTTP request failure? The best library I have come across is actually…

There's a decent Go library for various backoff algorithms. Useful if you're creating services which call webhooks: https://github.com/cenkalti/backoff

Re: APIs, robustness, and idempotency

#22

I'm shocked at how few HTTP libraries on GitHub properly handle exponential backoff, let alone retries. Do the Internet a favor, and file an issue with your favorite HTTP library asking them to implement exponential backoff. I haven't found anything in JS that does this properly though. Do people really just write apps that crap out upon the first HTTP request failure? The best library I have come across is actually…

It seems to me that OkHttp doesn't in fact support a retry back off.

https://github.com/square/okhttp/issues/2489

Re: APIs, robustness, and idempotency

#23
post #20
post #14

Earlier quoted context omitted.

Have you considered using the resource identifier as an idempotency key? Basically, have the client generate the ID (UUID, but namespaced on the server side [client+date]). This eliminates the need for the client to generate the idempotency key as well as the eliminates the need for the server to maintain an idempotency repository?

I think that would be a fine alternative to the system we have. I don't have a perfect history of events, but I suspect that our current design is basically the result of two things: 1. Idempotency keys as a concept were introduced quite a bit later than the API was originally conceived, so it made sense to make them an optional augmentation to existing integrations. 2. Our resource IDs have a fairly specific formats…

If you were to do it over again, would you have done it the same way? What would you have changed?

Re: APIs, robustness, and idempotency

#24
post #23
post #20

Earlier quoted context omitted.

I think that would be a fine alternative to the system we have. I don't have a perfect history of events, but I suspect that our current design is basically the result of two things: 1. Idempotency keys as a concept were introduced quite a bit later than the API was originally conceived, so it made sense to make them an optional augmentation to existing integrations. 2. Our resource IDs have a fairly specific formats…

If you were to do it over again, would you have done it the same way? What would you have changed?

Idempotency keys are a simple enough concept, that I think that they're mostly okay as is (we could have done a few smarter things on the server side implementation, but luckily that can still be fixed).

There are certainly a few things around HTTP semantics that Stripe got wrong. e.g. Most updates should probably be `PATCH` instead of `POST`, but it's probably not worth changing at this point.

Re: APIs, robustness, and idempotency

#25

I'm shocked at how few HTTP libraries on GitHub properly handle exponential backoff, let alone retries. Do the Internet a favor, and file an issue with your favorite HTTP library asking them to implement exponential backoff. I haven't found anything in JS that does this properly though. Do people really just write apps that crap out upon the first HTTP request failure? The best library I have come across is actually…

As the author of a http library (lua-http https://github.com/daurnimator/lua-http) that doesn't, I'm interested in how you'd want retries (not to mention exponential backoffs) to work:

- Should they be the default?

- What requests should be retried? (as much as we wish GETs were idempotent... they're not) see https://lists.w3.org/Archives/Public/ietf-http-wg/2017JanMar... for an intro to the complexities here

- What should get reused? (e.g. do new dns lookup? reuse connection? reuse proxy connection?)

- How to handle non-replayable pieces? (e.g. request bodys coming from a fifo)

- Usually a request has a timeout/deadline. should it be restarted for the retry? (probably not)

I haven't implemented retries yet, as the above questions seem hard to answer without knowing application/server specific qualities (and hence should be left to the user of the http library). Please feel free to file an issue :)

Re: APIs, robustness, and idempotency

#26
post #9

I authored this article and just wanted to leave a quick note on here that I'm more than happy to answer any questions, or debate/discuss the finer points of HTTP and API semantics ;) An ex-colleague pointed out to me on Twitter today that there are other APIs out there that have developed a concept similar to Stripe's `Idempotency-Key` header, the "client tokens" used in EC2's API for example [1]. To my knowledge th…

Is there any plan for the ability to discard previously used idempotency keys, so that a request with all the same parameters can actually be duplicated? Sometimes a payment will fail because a customer's card is declined (e.g. because of fraud detection or insufficient funds), and after the customer sorts it out, we'd like to try recharging their card, and not just receive the same error message. Our current workaround is to wait 24 hours for the idempotency key to expire, but it would be nice to be able to retry the request sooner without maintaining state on our side to generate a different idempotency key for the same payment.

Re: APIs, robustness, and idempotency

#27
The way stripe does the idempotency keys has always reminded me of two phase commit but I know that the two things are quite different. I wonder what in the distributed systems literature inspired this technique.

Re: APIs, robustness, and idempotency

#28
post #26
post #9

I authored this article and just wanted to leave a quick note on here that I'm more than happy to answer any questions, or debate/discuss the finer points of HTTP and API semantics ;) An ex-colleague pointed out to me on Twitter today that there are other APIs out there that have developed a concept similar to Stripe's `Idempotency-Key` header, the "client tokens" used in EC2's API for example [1]. To my knowledge th…

Is there any plan for the ability to discard previously used idempotency keys, so that a request with all the same parameters can actually be duplicated? Sometimes a payment will fail because a customer's card is declined (e.g. because of fraud detection or insufficient funds), and after the customer sorts it out, we'd like to try recharging their card, and not just receive the same error message. Our current workaro…

This is by design. If you want to make "another attempt", you should use a new idempotency key. Think of it as "one attempt/transaction/request" == "one idempotency key".

Re: APIs, robustness, and idempotency

#29
post #7
post #3

One thing about Stripe's API I have mixed feelings about is the liberal versioning. My experiencing with 100s of payment integrations is that they get done once and hopefully never touched again. I know most of Stripes updates are "additive" such that they are backwards compatible if coded liberally, but it can be confusing. Same with Lob.

(I work at Stripe.) API versioning is definitely a debatable subject, and I don't think that anyone at Stripe would claim that the current state of affairs is perfect by any means, but it's one that we think provides a good compromise between the stability of client integrations and our own ability to iterate on the API's design and make progress. The classic problem with web APIs is that unless you have a good versi…

If you don't mind me asking how exactly to you guys process requests with a versioned API?

Say I come in with a request for V2. How does that get directed to the V2 code path? What about services that are identical in V1 and V2. Do you have 2 copies of the same logic? Sorry for the naive question but API versioning is something that has been on my mind recently.

Re: APIs, robustness, and idempotency

#30

I'm shocked at how few HTTP libraries on GitHub properly handle exponential backoff, let alone retries. Do the Internet a favor, and file an issue with your favorite HTTP library asking them to implement exponential backoff. I haven't found anything in JS that does this properly though. Do people really just write apps that crap out upon the first HTTP request failure? The best library I have come across is actually…

As the author of a http library (lua-http https://github.com/daurnimator/lua-http ) that doesn't, I'm interested in how you'd want retries (not to mention exponential backoffs) to work: - Should they be the default? - What requests should be retried? (as much as we wish GETs were idempotent... they're not) see https://lists.w3.org/Archives/Public/ietf-http-wg/2017JanMar... for an intro to the complexities here - What…

That list of questions is why I prefer retry and back-off to be separate from the internals of the http library.

As a library user I need to work around the peculiarities of the particular service endpoints I'm integrating with. Backoff and retry aren't specific to the application/transport protocol through which a service is consumed.

For example, (in the java world) the approach in libraries like hysterix, guava-retrying, and failsafe https://github.com/jhalterman/failsafe#retries

Post reply on HN