Demo, all content is generated
Question

FastAPI BackgroundTasks sometimes just don't send the email

Open · 418 views · asked by greta_m · edited

After signup I do background_tasks.add_task(send_welcome_email, user.email). Most users get it, maybe 1 in 20 don't. No error in the logs that I can find. Deployed on Railway.

What I’ve tried

Added logging inside send_welcome_email, and for the missing ones the log line never appears. ChatGPT says to use Celery but that seems like a lot for one email.

Comment
Does Railway show restarts or deploys around the times the emails went missing? grace_mw · edited

3 answers

grace_mw · edited

BackgroundTasks run in the same process after the response is sent. If that process restarts (deploy, crash, Railway recycling the container, scaling down), queued tasks are simply gone. No retry, no trace. That fits "1 in 20, no log line".

For anything that must happen, use a real queue. Doesn't have to be Celery: arq or rq with Redis is ~20 lines. Or, simplest of all, a pending_emails table that a small cron picks up and marks sent.

Comment
marco_py · edited

I'd push back slightly: before adding infra, check whether the task is throwing. Exceptions in background tasks are easy to miss because the response already went out. Wrap the body in try/except with logger.exception. In my experience "silently missing" is more often an unhandled SMTP timeout than a restart. If it still goes missing with logging in place, then yes, a table + cron.

Comment
Fair point, check that first. Both can be true though. grace_mw · edited
Added the try/except. Will watch it for a few days. greta_m · edited
Update: found an SMTP timeout in the logs for 2 of them. Moving to a pending_emails table + cron anyway so it retries. greta_m · edited
abby_ops · edited

Easy way to confirm the restart theory on Railway: compare the timestamps of the missing emails with your deploy history and look for SIGTERM in the logs. If they line up, it's restarts.

Comment