Week 10: Background Work & Messaging

Build the next production-ready layer of your FastAPI service through clear concepts, a focused implementation and a practical exercise.

Module 7 of 12Week 10 of 15~3-4 HoursHands-on Exercise Included

By the end of this week, you'll be able to

  • Celery tasks and RabbitMQ
  • Delivery guarantees and idempotent consumers
  • Retries, dead-letter handling and the outbox pattern

1. Celery tasks and RabbitMQ

Start with the contract: make inputs, outputs and failure behavior explicit before adding infrastructure. This keeps the feature easy to reason about and gives tests a stable boundary.

2. Delivery guarantees and idempotent consumers

Apply the pattern through a small vertical slice. Keep framework wiring at the edge and business decisions in focused functions or services that can be tested without starting the whole application.

core example
@celery.task(bind=True, autoretry_for=(TemporaryError,), retry_backoff=True, max_retries=5)
def send_welcome_email(self, user_id: int):
    if email_log.already_sent(user_id):
        return
    mailer.send_welcome(user_id)

3. Retries, dead-letter handling and the outbox pattern

Treat failure paths as part of the design. Add bounded resource usage, meaningful errors and a verification step so the behavior remains dependable under real production conditions.

4. Hands-on Exercise

Build the feature

Publish a task-created event and consume it in an idempotent Celery worker. Demonstrate retry behavior without sending duplicate notifications.

Definition of done

  • The happy path works through the real HTTP boundary.
  • At least one failure path is handled and tested.
  • Configuration and secrets stay outside source code.
  • The README explains how to run and verify the result.

5. Knowledge Check

What does at-least-once delivery require from a consumer?

Show answer

The consumer must be idempotent because the same message may legitimately be delivered more than once.