POST /photos. The server-side handler (for example, savePhoto) validates the image, stores the original file in object storage (e.g., S3), writes metadata to the database, and triggers thumbnail creation.

resizePhoto) synchronously from savePhoto. In this design, the upload handler performs the resize before returning success to the client. If the resize is slow or gets stuck, the user experiences long waits or timeouts.

resizePhoto directly, savePhoto writes a small message to a queue (for example, a resize-photo queue) describing the job. Then savePhoto returns success to the client.


Why this decoupling helps
- Producers and consumers are independent: they do not need to know each other’s implementation or location.
- Producers return quickly and do not block on slow work.
- The queue acts as a buffer: it absorbs traffic spikes and stores work until consumers are ready.
- Workers can be scaled independently to increase processing throughput.
- If a worker crashes, the message remains in the queue until processed—improving fault tolerance.

- Make operations idempotent (safe to repeat).
- Or check whether work is already done before acting (e.g., a
processedflag in the database or checking object existence).

Message queues typically expose visibility timeouts and acknowledgement semantics. Consumers should acknowledge/delete messages only after successfully finishing their work. Implement idempotency checks or persistent flags so re-delivered messages do not cause duplicate side effects.
Summary
Message queues let you safely hand off long-running or unreliable tasks, decouple producers from consumers, buffer traffic spikes, and simplify scaling and recovery. Common real-world options include RabbitMQ and Amazon SQS. For operations with critical side effects, combine queues with idempotency checks, deduplication, or transactional outbox patterns.