AWS Developer Tools Blog

Introducing Automatic Request Batching for Amazon SQS in the AWS Java SDK 2.x

We are excited to introduce the Automatic Request Batching API for  Amazon Simple Queue Service (SQS) in the AWS SDK for Java 2.x. This feature allows client-side batching of up to 10 requests before sending them as a batch to Amazon SQS, optimizing both performance and cost. It also supports message polling to reduce the number of individual requests, boosting throughput while reducing costs.

Requirements

Before getting started, ensure that you’re using version 2.28.0 or later of the AWS Java SDK. You can find setup details in our “Set up an Apache Maven project” guide.

Add the following dependency to your pom.xml:

<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>sqs</artifactId>
    <version>2.28.0</version>
</dependency>

Quick walk-through for using SQS Automatic Request Batching APIs

Create a batch manager

Default configuration via SqsAsyncClient

The simplest way to create a batch manager is by using an SqsAsyncClient as shown in the following snippet.

SqsAsyncClient asyncClient = SqsAsyncClient.create();
SqsAsyncBatchManager sqsAsyncBatchManager = asyncClient.batchManager();

By default, all SqsAsyncBatchManager instances use the values shown in the Configuration options for SqsAsyncBatchManager in the following section. Additionally, the batch manager uses the client’s ScheduledExecutor by default.

Custom Configuration via SqsAsyncBatchManager.Builder

For advanced use cases, you can customize the batch manager with optional configurations using SqsAsyncBatchManager.Builder:

// Define all the necessary constants for the configuration used below (not shown here).
SqsAsyncBatchManager sqsAsyncBatchManager = SqsAsyncBatchManager.builder()
    .client(SqsAsyncClient.create())
    .scheduledExecutor(Executors.newScheduledThreadPool(SCHEDULED_THREAD_POOL_SIZE))
    .overrideConfiguration(b -> b
        .receiveMessageMinWaitDuration(MIN_WAIT_DURATION)
        .receiveMessageVisibilityTimeout(VISIBILITY_TIMEOUT)
        .receiveMessageAttributeNames(MESSAGE_ATTRIBUTE_NAMES)
        .receiveMessageSystemAttributeNames(SYSTEM_ATTRIBUTE_NAMES))
    .build();

Send messages

To send messages using the batch manager, use the sendMessage method. The SDK batches requests and sends them when either the batchSize (default: 10) is reached or the sendFrequency (default: 200 ms) interval elapses.

Example:

CompletableFuture<SendMessageResponse> sendMessageFuture = 
    sqsAsyncBatchManager.sendMessage(request -> 
        request.messageBody("Message Body")
               .queueUrl("https://sqs.us-east-1.amazonaws.com/123456789012/MyQueue"));

sendMessageFuture.thenAccept(response -> {
    System.out.println("Message sent successfully. Message ID: " + response.messageId());
}).exceptionally(throwable -> {
    System.err.println("Failed to send message: " + throwable.getMessage());
    return null;
});

Change message visibility

You can change the visibilityTimeout of messages in a batch using the changeMessageVisibility method.

Example:

CompletableFuture<ChangeMessageVisibilityResponse> changeVisibilityFuture =
    sqsAsyncBatchManager.changeMessageVisibility(request -> 
        request.receiptHandle("ReceiptHandle")
               .queueUrl("https://sqs.us-east-1.amazonaws.com/123456789012/MyQueue")
               .visibilityTimeout(30));

changeVisibilityFuture.thenAccept(response -> {
    System.out.println("Visibility timeout changed successfully.");
}).exceptionally(throwable -> {
    System.err.println("Failed to change message visibility: " + throwable.getMessage());
    return null;
});

Delete messages

To delete messages in a batch, use the deleteMessage method.

CompletableFuture<DeleteMessageResponse> deleteMessageFuture = 
    sqsAsyncBatchManager.deleteMessage(request -> 
        request.receiptHandle("ReceiptHandle")
               .queueUrl("https://sqs.us-east-1.amazonaws.com/123456789012/MyQueue"));

deleteMessageFuture.thenAccept(response -> {
    System.out.println("Message deleted successfully.");
}).exceptionally(throwable -> {
    System.err.println("Failed to delete message: " + throwable.getMessage());
    return null;
});

Receive messages

With default settings

When you continuously call receiveMessage in your application, the SqsAsyncBatchManager will deliver messages directly from its internal buffer, which the SDK updates in the background. This approach allows the SDK to retrieve and store extra messages in the buffer, enabling the SqsAsyncBatchManager to provide immediate responses from the buffer each time you call receiveMessage without waiting for a new request to SQS.

Example:

CompletableFuture<ReceiveMessageResponse> receiveMessageFuture = 
    sqsAsyncBatchManager.receiveMessage(request -> 
        request.queueUrl("https://sqs.us-east-1.amazonaws.com/123456789012/MyQueue"));

receiveMessageFuture.thenAccept(response -> {
    response.messages().forEach(message -> 
        System.out.println("Received message: " + message.body())
    );
}).exceptionally(throwable -> {
    System.err.println("Failed to receive messages: " + throwable.getMessage());
    return null;
});

With a custom request

If you want to customize the request further, for example by setting custom wait times and specifying the number of messages to retrieve, you can do so as follows:

CompletableFuture<ReceiveMessageResponse> receiveMessageCustomTimeoutFuture = 
    sqsAsyncBatchManager.receiveMessage(request -> 
        request.queueUrl("https://sqs.us-east-1.amazonaws.com/123456789012/MyQueue")
               .waitTimeSeconds(1)
               .maxNumberOfMessages(7));

receiveMessageCustomTimeoutFuture.thenAccept(response -> {
    response.messages().forEach(message -> 
        System.out.println("Received message with custom timeout: " + message.body())
    );
}).exceptionally(throwable -> {
    System.err.println("Failed to receive messages: " + throwable.getMessage());
    return null;
});

Note: For ReceiveMessageRequest, if any additional parameters, such as visibilityTimeout, messageAttributeNames, or requestOverrideConfiguration, are set, the receiveMessage API of the Batch Manager will bypass the internal buffer and send the request directly to SQS.

Configuration options for SqsAsyncBatchManager

SlNo Configuration Description Default value
1 maxBatchSize Maximum number of items per outbound request (SendMessageBatchRequest, ChangeMessageVisibilityBatchRequest, DeleteMessageBatchRequest). 10
2 sendRequestFrequency Time before sending a batch, unless maxBatchSize is reached earlier. Higher values may reduce requests but increase latency. 200ms
3 receiveMessageVisibilityTimeout Custom visibility timeout for messages. If unset, the queue’s default is used. Queue default
4 receiveMessageMinWaitDuration Minimum wait time for receiveMessage requests. Avoid setting to 0 to prevent CPU waste. 50ms
5 receiveMessageSystemAttributeNames List of system attributes to request for receiveMessage calls. None
6 receiveMessageAttributeNames List of attributes to request for receiveMessage calls. None

Conclusion

In this blog post, we showed you how to set up and begin using the Automatic Request Batching feature with the SqsAsyncBatchManager in the AWS SDK for Java 2.x. This feature is open-source and resides in the same repository as the AWS SDK for Java 2.0. For more examples related to SQS Automatic Request Batching, visit our Java SDK Developer Guide. We hope you’ll find this new feature useful. You can always share your feedback on our GitHub issues page.

About the author:

Hayden Baker

John Viegas

John Viegas serves as a Software Development Engineer on the Java SDK team at Amazon Web Services (AWS). With a passion for enhancing the developer experience, he actively engages in projects and tools designed to elevate software development. For further insights into his contributions, feel free to explore his GitHub profile under the handle @joviegas.