One Serverless Principle to Rule Them All: Idempotency [video]
youtube.com
youtube.com
-----
When it comes to serverless applications one principle rules them all: idempotency. This ability to rerun a function, make a REST API call, or process a message any number of times and ensure the same result is extremely hard to do reliably. In this talk, I’d like to explain and explore the importance of idempotency and discuss how we can implement it in our own systems, including:
1. Idempotency’s relationship with good serverless architecture.
2. How safe retries are impossible without idempotency.
3. Examples of serverless frameworks and tools that help/encourage idempotency.
You’ll leave this talk with a deeper understanding and appreciation for this tongue-twisting principle and start combing through your code with an idempotent eye.
They're not exactly formatted for nice reading, but on desktop it's possible to copy and paste the whole transcript wherever you like. I find the speech recognition astonishingly accurate. Of course you will still find mistakes, but overall it is almost always possible to get most of a video's content much faster just by reading the transcript.
I find text so much more accessible than video. Rarely have I seen a video that couldn't have been a bunch of slides or a blog post.
Unrelated to this video here, I started to wonder if that's why a lot of the content that tends to be associated with conspiracy theories or regarded disinformation is in the form of video and not text. Video is just so much harder to scrutinize and reason about because it's so difficult to reference specific arguments when they're talked about and not written down.
In other words, the decision to ship can be made idempotent. And that, in a modern software app, the result of a pretty complex set of things that can individually go wrong.
You could argue that Amazon made themselves something of a success by bringing at least the principle if not the actuality of idempotency to the shipment itself. By making it easy to get a replacement shipped.
Any concrete examples?
I was recently toying with an idea of a language where all side effects would be idempotent. Couldn't find any counterexamples.
I certainly support your toying, because I think a lot of impedance to idempotency is the lack of easy patterns to achieving it.
https://man7.org/linux/man-pages/man3/sem_post.3.html
-----
In fact, multithreaded synchronization in general is non-idempotent. You don't want to send a synchronize signal twice, you need to send it exactly as many times as necessary. (Ex: mutex lock / unlock, which is probably the simplest version of a sempahore that you can get. Semaphore of size 1)
Think about a mutex lock: if the semaphore (aka: mutex) is already locked, your signature is: sem_wait(mutex, 0, 0).
Which is not idempotent. Two "sem_waits(s, 0, 0)" mean that you need two (other) threads to unlock you. One sem_wait(s, 0, 0) means that only one other thread needs to unlock you.
------
Semaphores used in this manner are how you implement reader/writer locks, as well as thread barriers. (If 100 threads are in existence, you wait for 100 semaphore_posts from those 100 other threads).
None of the semaphores or mutexes are idempotent. And never can be.
Idempotency is a godsend for such actions.
If on the other hand, there is a side effect such as modifying the last_updated column then it isn't and should be coded appropriately.
As a trivial instance, you can guard a non-idempotent email send event with a database table and idempotency key. When you attempt to send the same message twice, you'll see that you have already done so.
With diligent engineering, this type of thinking can scale to non-trivial active-active concurrent writes and more.
So, while I find myself adamantly in agreement with the presenter —- idempotency is great, I don’t have much hope for the broader adoption of these ideas in driving meaningful improvements towards correctness. Serverless systems seem fated to approach Excel workbook levels of accuracy- it’ll work most of the time.
With the exception of things that can be trivially idempotent like pure referentially transparent functions and ffmpeg/image processing, of course.
Without idempotency your transient error retry logic becomes really complicated. You need to handle which stage(s) have completed successfully and which failed, which then makes your service stateful.
All this complexity comes from a lack of idempotency, if you can get rid of that, you could just Nack the message and let Pub/Sub retry it automatically with exponential backoff.
That seems more like a general systems principle.
While 10-40 is not a lot in the scale of hundreds of thousands of requests per day (were not that large), when that request is a write event, that's very detrimental to customer perception/experience... It might even cost your business money (failing to turn off/delete something)... And the easy answer of "retry the request" fails with write events that are not idempotent... WHEN should you retry? A gateway error doesn't necessarily mean the back end didn't get the request.. just that your didn't get a response.
It's even worse when what you'd expect to be internal communication has this same failure rate.. your back end processes getting a random 504 gateway error in places it never happened before.. breaking longer running processes.
Sorry low effort response, I'm on a phone. But my experience resonates with your comment a lot!
x ° x = x
Idempotency > Computer science meaning https://en.wikipedia.org/wiki/Idempotence#Computer_science_m...> Idempotence is the property of certain operations in mathematics and computer science whereby they can be applied multiple times without changing the result beyond the initial application. The concept of idempotence arises in a number of places in abstract algebra (in particular, in the theory of projectors and closure operators) and functional programming (in which it is connected to the property of referential transparency).
Ansible Glossary > Idempotency https://docs.ansible.com/ansible/latest/reference_appendices... :
> Idempotency: An operation is idempotent if the result of performing it once is exactly the same as the result of performing it repeatedly without any intervening actions
What makes this “serverless” rather than just good design, even if your API is on a traditional server?
We see something like .0001% failure rate with API gateway behind custom DNS, and supports response was "this is in SLA, try adding retry code" (which needs idempotency).
So we have to do extra engineering, including idempotency and bypassing API gateway in some cases, to mitigate the issue.