Live data from Hacker News

Idempotency is easy until the second request is different

blog.dochia.dev

11–20 of 244 posts

Re: Idempotency is easy until the second request is different

#11
post #8
post #6

Earlier quoted context omitted.

In your example, idempotency means same request + same state = same response. State becomes part of the request, that’s why it is hard.

That's just deterministic behaviour. For idempotency you literally just want f(state) = f(f(state)). Whether you achieve this by just doing the same thing twice (no external effects) or doing the thing exactly once (if you do have side effects) is not important. But if you have side effects and need something to happen exactly once it seems a lot more useful to communicate this, rather than pretending you did the thi…

[dead]

Re: Idempotency is easy until the second request is different

#13
The point of idempotency is safe retries. Systems are completely fallible, all the way down to the network cables.

The user wants something + the system might fail = the user must be able to try again.

If the system does not try again, but instead parrots the text of the previous failure, why bother? You didn't build reliability into the system, you built a deliberately stale cache.

Re: Idempotency is easy until the second request is different

#14
post #8
post #6

Earlier quoted context omitted.

In your example, idempotency means same request + same state = same response. State becomes part of the request, that’s why it is hard.

That's just deterministic behaviour. For idempotency you literally just want f(state) = f(f(state)). Whether you achieve this by just doing the same thing twice (no external effects) or doing the thing exactly once (if you do have side effects) is not important. But if you have side effects and need something to happen exactly once it seems a lot more useful to communicate this, rather than pretending you did the thi…

> But if you have side effects and need something to happen exactly once it seems a lot more useful to communicate this, rather than pretending you did the thing.

I think it depends on whether the sender needs to know whether the thing was done during the request, or just needs to know that the thing was done at all. If the API is to make a purchase then maybe all the caller really needs to know is "the purchase has been done", no matter whether it was done this time or a previous time.

And in terms of a caller implementing retry logic, it's easier for the caller to just retry and accept the success response the second time (no matter if it was done the second time, or actually done the first time but the response got lost triggering the retry).

Re: Idempotency is easy until the second request is different

#15
post #10
post #4

This seems to assume retrying a command should result in the same response, but I am not sure I agree. Idempotency is about state, not communication. Send the same payment twice and one of them should respond "payment already exists".

I don’t know if we’re reading the same article? The linked one states very plainly: ”Idempotency is about the effect An operation is idempotent if applying it once or many times has the same intended effect.”

I do not disagree with their definition of idempotency, but they silently assume resending the same result is the default. They discus this later on in the article but they do not seem to question why that might not be a good idea in the first place.

Edit: Perhaps it is my mental model that is different. I think it makes most sense to see the idempotency key as a transaction identifier, and each request as a modification of that transaction. From this perspective it is clearer that the API calls are only implying the expected state that you need to handle conflicts and make PUTs idempotent. Making it explicit clarifies things.

The article actually ends up creating the required table to make this explicit, but the API calls do not clarify their intent. As long as the transaction remains pending you're free to say "just set the details to X" and just let the last call win, but making the state final requires knowing the state and if you are wrong it should return an error.

If you split this in two calls there's no way to avoid an error if you set it from pending to final twice. So a call that does both at once should also crash on conflicts because one of the two calls incorrectly assumed the transaction was still pending.

Re: Idempotency is easy until the second request is different

#16
Idempotency means f(x) = f(f(x)).*

Here x is interpreted as state and f an action acting on the state.

State is in practice always subjected to side effects and concurrency. That's why if x is state then f can never be purely idempotent and the term has to be interpreted in a hand-wavy fashion which leads to confusions regarding attempts to handle that mismatch which again leads to rather meandering and confusing and way too long blog posts as the one we are seeing here.

*: I wonder how you can write such a lengthy text and not once even mention this. If you want to understand idempotency in a meaningful way then you have to reduce the scenario to a mathematical function. If you don't then you are left with a fuzzy concept and there isn't much point about philosophizing over just accepting how something is practically implemented; like this idempotency-key.

Re: Idempotency is easy until the second request is different

#17
post #13

The point of idempotency is safe retries. Systems are completely fallible, all the way down to the network cables. The user wants something + the system might fail = the user must be able to try again. If the system does not try again, but instead parrots the text of the previous failure, why bother? You didn't build reliability into the system, you built a deliberately stale cache.

"Idempotency" feels like "encapsulation" all over again.

Take a good principle like 'modules should keep their inner workings secret so the caller can't use it wrong', run it through the best-practise-machine, and end up with 'I hand-write getters and setters on all my classes because encapsulation'.

Re: Idempotency is easy until the second request is different

#18
I really hate the POST verb for RESTish APIs because it cannot be idempotent without implementing an idempotency layer. Other verbs are naturally idempotent. Has anyone tried foregoing POST routes entirely? Theoretically you can let the client generate an ID and have it request a PUT route to create new entities. This would give you a tiny amount of extra complexity on the client, but make the server simpler as a trade-off.

Re: Idempotency is easy until the second request is different

#20
post #4

This seems to assume retrying a command should result in the same response, but I am not sure I agree. Idempotency is about state, not communication. Send the same payment twice and one of them should respond "payment already exists".

> Send the same payment twice and one of them should respond "payment already exists".

You are hiding the relevant complexity in the term "same". What is here the same? I mean, if accidentally buy only 1 instead of two items of a product and then buy afterwards again 1 item. How is this then the same or not the same payment?

Post reply on HN