Code like your example is likely the reason, why all those people in this thread warn you about the issues of not having transactional guarantees with external services. In elixir you can just as well do this, which is about the same as your example:
{:ok, user} = MyApp.Repo.insert(user)
case user |> Email.registration |> Mailer.deliver do
:ok -> :ok
error -> …
end
But as mentioned before this code no matter the language does have problems. For example saving the user could succeed, but the machine/service crashes before Mailer.deliver
is called. I’m not sure what MTA means, but if it’s your mailing provider, there’s nothing for them to do about this. They can’t see the crash. In this specific case even your mailing library won’t help you, as even that wasn’t yet called.
Generally I feel in the elixir community there are many people of experience, which might have been burned by exactly such problems unlikely as one might imagine them. Given the beam and the ecosystem also provides a bunch of very nice tooling – like e.g. oban for persistent queues in most people’s default postgres db – which allows you to model the problem in a way, which acknowledges the issue of the task we tend do suggest using those instead of the straight forward, but problematic solution.
In this case a persistent queue – as mentioned before – makes the transaction of saving the user simpler and actually transactional (so in case of a crash you either have no user or a user and a persisted task for sending an email), while sending the email by executing the queue is the only place where you have to deal with the external service. Only here you’ll deal with timeouts, retrys and eventually stop trying if things keep failing. It’s still the same issues as without the persistent queue, but it’s separated from saving the user (doesn’t affect more code than it needs) and you’ll get a proper history of how many retrys you had, what the error(s) were and you can e.g. be notified if you need to manually resolve something. For the proposed problem in the start of this post nobody would even know that a mail wasn’t sent.