Cloud Parts

Background jobs with a queue

The API drops slow work onto SQS and returns at once; a pool of Fargate workers drains the queue at a steady pace.

Fits: Any app with slow or bursty side work4 technologies
Live model
What you’re watchingUploads arrive in bursts. The API enqueues a job for each and moves on. The queue only hands a job to a worker that has room, so the backlog grows during a burst and drains steadily after it. Results land in S3.

Click any box to open its page. Open it in the playground to rewire it, change the traffic or take parts down.

Some work is too slow to do while a user waits: resizing a video, generating a PDF, calling a flaky partner API. The API puts a message describing the job on a queue and responds right away. Workers pull jobs when they have capacity, so a sudden burst piles up in the queue instead of overwhelming anything, and a crashed worker’s job simply becomes visible again for another worker.

How it flows

  1. 1

    The API enqueues and returns

    For each upload, the API sends a small message such as {"job": "thumbnail", "key": "uploads/123.jpg"} to SQS and replies 202 Accepted. The user isn’t kept waiting for the processing.

  2. 2

    Workers pull when they’re free

    Each worker long-polls the queue, takes a job, and the message becomes invisible to others for the visibility timeout. During a burst the queue absorbs the excess instead of the workers.

  3. 3

    Success deletes the message

    When the thumbnail is written to S3, the worker deletes the message. If the worker crashes first, the message reappears after the timeout and another worker retries it.

  4. 4

    Scale on queue depth

    An autoscaling rule watches how many messages are waiting and adds workers when the backlog grows, then removes them when it’s empty.

Why this shape works

  • Users get fast responses regardless of how slow the job is
  • Bursts are smoothed out: workers run at a steady rate instead of falling over
  • Retries come for free, and a dead-letter queue catches jobs that keep failing
  • API and workers scale and deploy independently

Where it strains

  • Standard SQS queues can deliver a message more than once; make jobs idempotent
  • Set the visibility timeout longer than your slowest job, or jobs run twice
  • Users need a way to learn the job finished: polling, a webhook or a notification
  • A growing backlog is a silent failure; alert on the age of the oldest message

Common swaps

  • Short jobs (under 15 minutes)? Let Lambda consume the queue directly and skip managing workers.

  • Self-hosted, or need routing and priorities? RabbitMQ is the classic open-source broker for this.

  • Already on Postgres? pgmq or PgQueuer keep jobs in the same database, so a job can be enqueued in the same transaction as the data it’s about.

  • Multi-step jobs with retries per step and long waits fit a workflow engine better than a bare queue.

Built from

Architectures with parts in common

Worth exploring

All resources →
Article· April 2026Keeping a Postgres queue healthySimeon Griggs, PlanetScaleWhy a busy queue table fills with dead rows, and how one long query elsewhere can stop vacuum from cleaning them up and slow every dequeue. The diagnosis applies to any Postgres; the fix it ends on, Traffic Control, exists only on PlanetScale.
Video· April 2022Queues in PostgreSQLThomas Munro, PostgreSQL committer, at Citus Con 2022A Postgres developer walks through what queue-like workloads do inside the database, and the complications of using Postgres as a job or message queue.

Sources

Improve this page on GitHub