AWS
SQS
Message Queuing
Cloud Computing
Data Processing

Retrieve multiple messages from SQS

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

When you consume Amazon SQS efficiently, you usually do not receive one message at a time. SQS lets you request up to 10 messages in a single ReceiveMessage call, which reduces API overhead and improves throughput. The important part is that receiving a batch is only half the job; you also need visibility-timeout handling and deletion after successful processing.

The Main SQS Limit to Remember

The ReceiveMessage API can return at most 10 messages per request. That means “multiple messages” in SQS really means a batch of up to 10, not an arbitrary large pull.

The most useful parameters are:

  • 'MaxNumberOfMessages: maximum messages to return, up to 10'
  • 'WaitTimeSeconds: enables long polling'
  • 'VisibilityTimeout: controls how long received messages stay hidden from other consumers'
  • 'MessageAttributeNames: if you need custom message attributes'

A Boto3 Example

This Python example receives up to 10 messages with long polling.

python
1import boto3
2
3sqs = boto3.client("sqs", region_name="us-east-1")
4queue_url = "https://sqs.us-east-1.amazonaws.com/123456789012/my-queue"
5
6response = sqs.receive_message(
7    QueueUrl=queue_url,
8    MaxNumberOfMessages=10,
9    WaitTimeSeconds=10,
10    VisibilityTimeout=30,
11    MessageAttributeNames=["All"],
12)
13
14messages = response.get("Messages", [])
15
16for message in messages:
17    print("MessageId:", message["MessageId"])
18    print("Body:", message["Body"])

If the queue is empty, Messages may be missing entirely, so the get(..., []) pattern matters.

Delete Messages After Successful Processing

Receiving a message does not remove it from the queue. SQS hides it temporarily using the visibility timeout. After you process it successfully, delete it explicitly.

python
1entries = []
2
3for message in messages:
4    # Process the message here
5    print("Processed:", message["MessageId"])
6    entries.append(
7        {
8            "Id": message["MessageId"],
9            "ReceiptHandle": message["ReceiptHandle"],
10        }
11    )
12
13if entries:
14    sqs.delete_message_batch(QueueUrl=queue_url, Entries=entries)

Batch deletion reduces API calls just like batch receipt does.

Why Long Polling Matters

If you call ReceiveMessage repeatedly with short polling, you can waste requests and still get empty responses even when messages are arriving.

Setting WaitTimeSeconds to a positive value enables long polling. That makes the consumer wait briefly for available messages, which usually lowers cost and improves efficiency.

Long polling is often the default recommendation unless you have a very specific low-latency polling requirement.

Visibility Timeout Is Part of Correctness

If processing takes longer than the visibility timeout, the message can become visible again before your worker finishes. That leads to duplicate processing.

So choose the timeout to match realistic processing duration, or extend it while work is still in progress.

This is especially important because SQS is designed for at-least-once delivery. Your consumer should already be prepared for duplicate deliveries.

Batch Processing Strategy

A good consumer loop usually does this:

  1. receive up to 10 messages
  2. process them one by one or in a small internal batch
  3. delete only the messages that were handled successfully
  4. leave failed ones undeleted so they can return after visibility expires

That pattern works well with retry logic and dead-letter queues.

Common Pitfalls

A common mistake is assuming that receiving a message removes it. It does not. You must delete it after successful processing.

Another mistake is setting MaxNumberOfMessages=10 and expecting exactly 10 every time. SQS returns up to 10, not a guaranteed full batch.

A third issue is using short polling with high request frequency and then wondering why SQS cost is higher than expected.

Summary

  • SQS can return up to 10 messages per ReceiveMessage call
  • Use long polling with WaitTimeSeconds for better efficiency
  • Messages are hidden after receipt, not deleted
  • Delete processed messages explicitly, preferably with DeleteMessageBatch
  • Match visibility timeout to processing time so messages do not reappear too early

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.