Skip to content

Commit 984750f

Browse files
authored
Merge pull request #3698 from aws/joviegas/stag_sqs_req_mem_leak
bugfix: Fixed memory leak issue in SqsBatchManager for RequestBatchManager sendRequest Calls in SqsBatchManager
2 parents fbbeb74 + d16a75d commit 984750f

File tree

3 files changed

+18
-7
lines changed

3 files changed

+18
-7
lines changed

.changes/2.30.31.json

+6
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@
5555
"category": "AWS SDK for Java v2",
5656
"contributor": "",
5757
"description": "Updated endpoint and partition metadata."
58+
},
59+
{
60+
"type": "bugfix",
61+
"category": "Amazon Simple Queue Service",
62+
"contributor": "",
63+
"description": "Fixed memory leak in SqsBatch Manager: Resolved an issue where pendingResponses and pendingBatchResponses collections in RequestBatchManager retained references to completed futures, causing memory accumulation over time."
5864
}
5965
]
6066
}

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@
3636
- ### Features
3737
- Added a mandatory parameter DataAutomationProfileArn to support for cross region inference for InvokeDataAutomationAsync API. Renamed DataAutomationArn to DataAutomationProjectArn. Added APIs to support tagging.
3838

39+
## __Amazon Simple Queue Service__
40+
- ### Bugfixes
41+
- Fixed memory leak in SqsBatchManager: Resolved an issue where pendingResponses and pendingBatchResponses collections in RequestBatchManager retained references to completed futures, causing memory accumulation over time.
42+
3943
# __2.30.30__ __2025-02-27__
4044
## __AWS SDK for Java v2__
4145
- ### Features

services/sqs/src/main/java/software/amazon/awssdk/services/sqs/internal/batchmanager/RequestBatchManager.java

+8-7
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717

1818
import java.time.Duration;
1919
import java.util.ArrayList;
20-
import java.util.Collections;
2120
import java.util.List;
2221
import java.util.Map;
2322
import java.util.Optional;
@@ -58,15 +57,16 @@ protected RequestBatchManager(RequestBatchConfiguration overrideConfiguration,
5857
this.maxBatchItems = batchConfiguration.maxBatchItems();
5958
this.sendRequestFrequency = batchConfiguration.sendRequestFrequency();
6059
this.scheduledExecutor = Validate.notNull(scheduledExecutor, "Null scheduledExecutor");
61-
pendingBatchResponses = Collections.newSetFromMap(new ConcurrentHashMap<>());
62-
pendingResponses = Collections.newSetFromMap(new ConcurrentHashMap<>());
60+
pendingBatchResponses = ConcurrentHashMap.newKeySet();
61+
pendingResponses = ConcurrentHashMap.newKeySet();
6362
this.requestsAndResponsesMaps = new BatchingMap<>(overrideConfiguration);
6463

6564
}
6665

6766
public CompletableFuture<ResponseT> batchRequest(RequestT request) {
6867
CompletableFuture<ResponseT> response = new CompletableFuture<>();
6968
pendingResponses.add(response);
69+
response.whenComplete((r, t) -> pendingResponses.remove(response));
7070

7171
try {
7272
String batchKey = getBatchKey(request);
@@ -120,16 +120,17 @@ private void flushBuffer(String batchKey, Map<String, BatchingExecutionContext<R
120120
flushableRequests.forEach((contextId, batchExecutionContext) ->
121121
requestEntries.add(new IdentifiableMessage<>(contextId, batchExecutionContext.request())));
122122
if (!requestEntries.isEmpty()) {
123-
CompletableFuture<BatchResponseT> pendingBatchingRequest = batchAndSend(requestEntries, batchKey)
124-
.whenComplete((result, ex) -> handleAndCompleteResponses(result, ex, flushableRequests));
125-
123+
CompletableFuture<BatchResponseT> pendingBatchingRequest = batchAndSend(requestEntries, batchKey);
126124
pendingBatchResponses.add(pendingBatchingRequest);
125+
pendingBatchingRequest.whenComplete((result, ex) -> {
126+
handleAndCompleteResponses(result, ex, flushableRequests);
127+
pendingBatchResponses.remove(pendingBatchingRequest);
128+
});
127129
}
128130
}
129131

130132
private void handleAndCompleteResponses(BatchResponseT batchResult, Throwable exception,
131133
Map<String, BatchingExecutionContext<RequestT, ResponseT>> requests) {
132-
requests.forEach((contextId, batchExecutionContext) -> pendingResponses.add(batchExecutionContext.response()));
133134
if (exception != null) {
134135
requests.forEach((contextId, batchExecutionContext) -> batchExecutionContext.response()
135136
.completeExceptionally(exception));

0 commit comments

Comments
 (0)