Ask HN: How to make server side code atomic?
Imagine the following:
1. You submit some value to the DB
2. After that value is submitted, you need to do a POST to an email API
Your server could crash between steps 1 & 2, resulting in the email never being sent.
What is the common accepted solution here? The only thing I can think of is temporal.io, but many, many pieces of software have been built before temporal.io.
23 comments
[ 0.29 ms ] story [ 66.3 ms ] threadWithout two phase commits I would
1) Write to the DB in the original POST request a record indicating that an email should be sent 2) Process that record outside of the original request and mark it as sent
This would be fine in the case of email servers (you just end up sending the email twice). It seems a lot less fine in the case of Stripe transactions.
I guess, the concept of idem-potency keys can solve this issue. (https://brandur.org/idempotency-keys)
Almost makes me forgive the interview process tech-companies demand just to check dev's can actually cover the basics.
Which is sad, this is more likely a bit of information a dev would need to know, instead of inverting a binary tree.
You have service A that checks if it needs to send an email.
Service B submits a value to DB and adds a task to the email system inside a transaction. If the DB is down, the service will retry later. If the email service isn't responding, it can roll back the DB change.
During the first database commit, set a field indicating that the associated email is pending. After sending it and getting a success, do another database commit setting the flag to sent.
You will need a server-side task, maybe a cron job, to periodically query the database for pending emails and attempt to resend them, then set the flag to sent. Also, hopefully the API you use to send email has a way to avoid duplicate emails, perhaps by attaching a unique ID to the request that's used to detect duplicate sends.
I think this is the interesting part. Storing a value in the table to be processed by a queue seems normal / not rocket science. But what happens when we 1. Call the API 2. The API succeeds 3. We crash before we can write success
Now we'll send duplicate emails. I don't think all APIs have ways to avoid duplicate emails/transactions, so that could be a hairy problem.
For email, I think the occasional duplicate is usually better. (Effectively, it's up to the email recipient to ignore the duplicate.)
Now you've got the /api invoked, but no DB write.
Edit: Actually the worst case is pretty bad, you could accidentally double-charge a user using Stripe.
It boils down to choosing between: