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.
Almost makes me forgive the interview process tech-companies demand just to check dev's can actually cover the basics.
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.
It boils down to choosing between:
- possibility of sending 0-1 emails
- possibility of sending 1+ emails (in reality is 0+,your service could still go down permanently)
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.
Edit: Actually the worst case is pretty bad, you could accidentally double-charge a user using Stripe.
begin transaction;
write to db;
post /api
commit;
Assuming rollback is implicit when an exception occurs, failure at any point results in the whole operation not executing.