SQS Queues, Visibility Timeout, Long Polling, Standard vs FIFO
coreintermediateAn SQS queue holds messages until a consumer processes and deletes them. When a consumer receives a message, it stays in the queue but becomes invisible for the visibility timeout — if the consumer does not delete it in time, it reappears for another consumer. Long polling waits up to 20 seconds for a message instead of returning empty immediately, cutting wasted API calls. A standard queue has unlimited throughput but only best-effort ordering; a FIFO queue guarantees strict order within a message group, at a much lower throughput ceiling.
Think of it as
A message is like a claim ticket at a coat check: receiving it does not remove it from the rack, it just flips a "reserved" flag (the visibility timeout) so nobody else grabs the same coat. If you never come back to claim it (delete it), the flag clears and someone else can take it. Long polling is the difference between an attendant who checks the rack once and shrugs if it is empty, versus one who watches the door for up to 20 seconds before giving up.
What we're doing: See why a consumer that takes longer than the visibility timeout causes the same message to be processed twice.
- 1
- The visibility timeout is shorter than the actual processing time — the root cause.
- 4
- A second consumer receiving the reappeared message is expected SQS behavior, not a bug — the queue has no way to know Consumer A is still working.
Why this works: SQS is at-least-once, not exactly-once (except FIFO's within-group exactly-once processing guarantee) — a visibility timeout shorter than real processing time is one of the most common ways a duplicate delivery actually happens in production, and it is entirely avoidable by sizing the timeout to the job.
Leaving the visibility timeout at the 30-second default for a slow job
Wrong
Better
What you see: The same message gets processed by more than one consumer concurrently, and CloudWatch shows ApproximateReceiveCount climbing on messages that were never actually stuck.
Why: The default (30s) is a generic starting point, not a recommendation for any specific job — a job that runs longer than the timeout guarantees a duplicate receive, regardless of how reliable the consumer code is.
- Standard
- Nearly unlimited throughput per API action
- Best-effort ordering — messages can arrive out of order
- At-least-once delivery — duplicates are possible
- FIFO
- 300 TPS per API action by default (3,000 msg/sec batched)
- Strict order guaranteed within a MessageGroupId
- Deduplication window (default 5 min) prevents duplicate sends
Remember: Visibility timeout hides a received message so only one consumer works it; it reappears if not deleted in time — size it to the job. Long polling (up to 20s) avoids wasted empty responses. Standard = unlimited throughput, best-effort order; FIFO = strict order per MessageGroupId, ~300 TPS default ceiling, dedup window prevents repeat sends.
See also: sqs dlq redrive and idempotent consumers · visibility timeout sizing and extension

