Visibility Timeout
How long a message is hidden after a consumer receives it.
Prevents two workers from processing the same message at the same time. Misconfiguring it is the #1 source of duplicate processing bugs.
What it is
When a consumer receives a message, it remains in the queue but becomes temporarily invisible to other consumers. The visibility timeout controls how long that invisibility lasts. Other consumers cannot process the same message until the timeout expires or the message is deleted.
Message lifecycle
After ReceiveMessage, you are expected to process and delete the message before the visibility timeout expires. If you don't, the message becomes visible again and can be retrieved by the same or a different consumer.
- Manual deletion: call DeleteMessage after successful processing.
- Some AWS SDKs support automatic deletion on successful processing.
Configuration
Set visibility timeout at the queue level via SetQueueAttributes, or override per-message with ChangeMessageVisibility. You can also terminate visibility early by setting VisibilityTimeout to 0.
- Default: 30 seconds.
- Range: 0 seconds to 12 hours.
- Maximum 12-hour limit is from first receive — extending timeout does not reset this ceiling.
// Extend while processing (heartbeat)
ChangeMessageVisibility({
QueueUrl,
ReceiptHandle,
VisibilityTimeout: 120, // seconds
})Standard vs FIFO behavior
In both queue types, visibility timeout prevents simultaneous processing. Because of at-least-once delivery, SQS does not guarantee a message won't be delivered more than once within the visibility period. For FIFO queues, messages in the same MessageGroupId are not available until the in-flight message is deleted or times out — preserving order within the group.
In-flight messages and quotas
In-flight messages are those received but not yet deleted. Standard queues have a limit of approximately 120,000 in-flight messages. With short polling, exceeding this limit returns an OverLimit error; with long polling, no new messages are returned until the count drops.
- Delete messages promptly after processing.
- Monitor in-flight count with CloudWatch.
- Distribute load across multiple queues if needed.
Best practices
Start with a timeout matching your maximum processing time. Use a heartbeat (periodic ChangeMessageVisibility) for long-running tasks. Pair with a DLQ for messages that fail repeatedly.
- Rule of thumb: ~6× your p99 processing time.
- Too low → duplicates; too high → slow recovery from crashed workers.
- For processing beyond 12 hours, use Step Functions or break work into smaller steps.
- !If processing takes longer than the visibility timeout, the same message is delivered to another consumer — guaranteed duplicates.
- !For long-running jobs, call ChangeMessageVisibility periodically as a heartbeat instead of setting one giant timeout.
- !The 12-hour maximum is from first receive — extending visibility does not reset this limit.