Federico Mariani created CAMEL-26649:
----------------------------------------

             Summary: camel-aws2-sqs - consumer receives one message per 
ReceiveMessage and deletes messages one by one by default
                 Key: CAMEL-26649
                 URL: https://issues.apache.org/jira/browse/CAMEL-26649
             Project: Camel
          Issue Type: Improvement
          Components: camel-aws2-sqs
    Affects Versions: 4.18.5, 4.23.0, 4.22.2
            Reporter: Federico Mariani


h3. Problem
By default the {{aws2-sqs}} consumer asks SQS for one message per 
{{ReceiveMessage}} call, and it deletes every routed message with its own 
synchronous {{DeleteMessage}} call. Line numbers are on main (7978db3d42dd):
* 
{{components/camel-aws/camel-aws2-sqs/src/main/java/org/apache/camel/component/aws2/sqs/Sqs2Endpoint.java}}
 line 104: {{maxMessagesPerPoll}} is an {{int}} with no default (0). Its 
javadoc (line 437) and the catalog say "Is default unlimited".
* {{Sqs2Consumer.java}} line 693: {{Math.max(1, 
endpoint.getMaxMessagesPerPoll())}}, so 0 or a negative value means 1, and line 
797 sends {{maxNumberOfMessages(1)}}. Values above 10 are already split into 
receives of at most 10 (CAMEL-21031).
* {{Sqs2Configuration.java}} line 78: {{waitTimeSeconds}} has no default, so no 
{{WaitTimeSeconds}} is sent. The queue attribute 
{{ReceiveMessageWaitTimeSeconds}} then applies, which means short polling 
unless the queue sets it above 0.
* {{Sqs2Consumer.java}} lines 263-270: {{processCommit}} calls 
{{deleteMessage}} once per exchange. The visibility extender already batches, 
with {{ChangeMessageVisibilityBatch}} (lines 524-544).

With the defaults ({{delay=500}}, {{greedy=false}}) a consumer thread gets at 
most about 2 messages per second, at 2 billable requests per message. Yet SQS 
returns up to 10 messages per receive (AWS SDK 2.57.7 service model: "Valid 
values: 1 to 10. Default: 1."), and {{DeleteMessageBatch}} takes up to 10 
entries. The effective default has always been 1: before CAMEL-21031 the 
consumer did not send {{MaxNumberOfMessages}} at all, and the SQS default is 1. 
The words "default unlimited" come from the generic batch consumer and are 
wrong here.

h3. How to reproduce
These numbers are measured. The route is 
{{from("aws2-sqs://MyQueue?amazonSQSClient=#client&initialDelay=0" + 
options)}}, run on the module's {{AmazonSQSClientMock}} with 30 messages 
queued; it records every request and stops once N messages have been routed:
||options||messages routed||ReceiveMessage 
calls||MaxNumberOfMessages||exchanges per poll||DeleteMessage calls||
|(defaults)|5|5|1|1|5, in 2.1 s|
|{{maxMessagesPerPoll=0}} or {{-1}}|2|2|1|1|2|
|{{greedy=true}}|30|31|1|1|30|
|{{concurrentConsumers=3}}|6|6|1|1|6|
|{{maxMessagesPerPoll=10}} (control)|30|3|10|10|30|
|{{maxMessagesPerPoll=25}} (control)|25|3|10, 10, 5|25|25|
No request carried {{WaitTimeSeconds}}, and {{DeleteMessageBatch}} was never 
called. {{greedy}} only removes the delay between polls, and 
{{concurrentConsumers}} only adds threads; neither changes the batch size.

h3. Proposed change
# Default {{maxMessagesPerPoll}} to 10. Fix the javadoc and catalog text: 0 or 
a negative value means one message per receive, and above 10 the consumer sends 
several receives of at most 10.
# Add an opt-in option that collects the receipt handles of completed exchanges 
and sends {{DeleteMessageBatch}} on the existing sync {{SqsClient}}. It flushes 
at 10 handles, at the end of the poll and on stop/suspend, and reports failed 
entries one by one as today. The SDK's {{SqsAsyncBatchManager}} does not fit: 
it needs an {{SqsAsyncClient}} ({{Builder.client(SqsAsyncClient)}}), and 
{{batchManager()}} is generated only on the async client.
# Optionally, document long polling ({{waitTimeSeconds}}), or default to it. 
With short polling SQS samples only some of its servers and can return fewer 
than 10 messages while more are queued. So (1) alone gives up to 10x fewer 
receives, not a guaranteed 10x; long polling is what makes full batches 
reliable.

Risks:
* Visibility timeout vs. a batch of 10. The 10 messages of a poll are routed 
one after the other, and the visibility timeout of each one starts at the 
receive. With a slow synchronous route and without {{extendMessageVisibility}}, 
the last messages of a batch can become visible again and be delivered twice. 
With {{extendMessageVisibility=true}} the whole batch is extended from the 
receive since CAMEL-25700 (4.24.0).
* Deferred deletes widen the window in which a crash leaves already processed 
messages to be delivered again. The extender must keep extending a message 
until its delete is flushed.

Estimates (not measured against AWS): with full batches, (1) and (2) bring 
billable requests from 2 down to about 0.2 per message.

h3. Impact / upgrade
* (1) changes a default, so it needs a {{camel-aws2-sqs}} entry in the 4.24 
upgrade guide. The entry should say that each poll now takes up to 10 messages, 
repeat the visibility-timeout point above, and give {{maxMessagesPerPoll=1}} to 
keep the old behaviour.
* (2) is opt-in and has no upgrade impact.
* camel-kamelets also needs a change: the {{aws-sqs-source}} Kamelet 
(camel-kamelets 4.23.0) declares {{maxMessagesPerPoll}} with {{default: 1}} and 
{{maximum: 10}} and always passes it. Kamelet users therefore keep one message 
per receive whatever the component default is, and the maximum of 10 is out of 
date since CAMEL-21031 started splitting larger values.
* The same code is on camel-4.18.5, camel-4.22.2 and camel-4.23.0.

h3. Related
* CAMEL-21031 (1432192c6ca3) added polling of more than 10 messages and 
{{Math.max(1, ...)}}; its description notes that the consumer receives only 1 
message by default.
* CAMEL-7590 (2014, resolved as Information Provided) asked for batch 
write/delete through the SDK v1 buffered async client.
* CAMEL-19656 batched the visibility extender; CAMEL-25700 extends the whole 
batch with {{extendMessageVisibility}}.
* CAMEL-9592 documented {{maxMessagesPerPoll}} together with 
{{concurrentConsumers}}.

_Claude Code on behalf of Federico Mariani_



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to