[
https://issues.apache.org/jira/browse/CAMEL-25660?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18127384#comment-18127384
]
Andrea Cosentino commented on CAMEL-25660:
------------------------------------------
h4. The 4096 limit is real - withdrawing my retraction
In the previous description I retracted the 4096 figure, on the grounds that
Azure's dead-letter concept page and quotas page document only the 256 KB
message quota and that the Java SDK's {{DeadLetterOptions}} does no validation.
That retraction was wrong, and review on the PR caught it.
The limit is in the SDK sources, verified by fetching them:
* azure-sdk-for-net,
{{sdk/servicebus/Azure.Messaging.ServiceBus/src/Constants.cs}}: {{public const
int MaxDeadLetterReasonLength = 4096;}}
* the same repo, {{Amqp/AmqpReceiver.cs}}, at the top of
{{DeadLetterInternalAsync}}: {{Argument.AssertNotTooLong(deadLetterReason,
Constants.MaxDeadLetterReasonLength, ...)}} and
{{Argument.AssertNotTooLong(deadLetterErrorDescription,
Constants.MaxDeadLetterReasonLength, ...)}} - so *both* fields, against the
reason constant, before either disposition path.
* azure-sdk-for-js, {{sdk/core/core-amqp/src/util/constants.ts}}:
{{maxDeadLetterReasonLength: 4096}}.
Two independent SDKs capping both fields at 4096 is good evidence of a
service-side constraint even though no doc states it. My reasoning failed
because it rested on two absences - no number in the prose docs, and no check
in the Java SDK - and the Java SDK turned out to be the outlier.
So the fix caps both fields at 4096 rather than the 1024/8192 first proposed,
leaving room for the three-character ellipsis so the result still fits.
The 256 KB message quota quoted earlier is still real and still a reason to
bound the stack trace; it is simply not the only or the tightest constraint.
_Claude Code on behalf of oscerd_
> camel-azure-servicebus - dead-lettering builds unbounded reason and
> description from the exception, and a failure to dead-letter is not caught
> ----------------------------------------------------------------------------------------------------------------------------------------------
>
> Key: CAMEL-25660
> URL: https://issues.apache.org/jira/browse/CAMEL-25660
> Project: Camel
> Issue Type: Bug
> Components: camel-azure-servicebus
> Reporter: Andrea Cosentino
> Assignee: Andrea Cosentino
> Priority: Major
>
> h3. Summary
> With {{enableDeadLettering=true}} in PEEK_LOCK mode,
> {{ServiceBusConsumer.ConsumerOnCompletion.onFailure}} dead-letters the
> message with a reason and a description built from the route's exception. Two
> problems:
> # The call is not guarded, so a rejected dead-letter request escapes
> {{onFailure}} and the message is never dead-lettered at all.
> # Neither field is bounded, so Camel does nothing to keep the message under
> the size quota that Azure's own documentation warns about for exactly this
> practice.
> h3. The unguarded call
> {code:java}
> try {
> ...
> messageContext.deadLetter(deadLetterOptions);
> ...
> } finally {
> pendingExchanges.decrementAndGet();
> }
> {code}
> There is no {{catch}}. If the broker rejects the request, the exception
> leaves {{onFailure}} into the Azure SDK's processor callback, and nothing
> reports it through the consumer's configured {{ExceptionHandler}}. The
> message stays locked, the lock expires, Service Bus redelivers it, the route
> fails the same way - and this repeats until {{maxDeliveryCount}} is reached,
> at which point the broker dead-letters it itself with reason
> {{MaxDeliveryCountExceeded}}. The outcome is that the diagnostics
> {{enableDeadLettering}} exists to provide are exactly what gets lost, and the
> exchange is processed several more times than intended.
> {{onComplete}} has the same unguarded shape around
> {{messageContext.complete()}}, which is worth deciding on at the same time.
> h3. The unbounded fields
> {code:java}
> deadLetterOptions.setDeadLetterReason(
> String.format("%s: %s", cause.getClass().getName(),
> cause.getMessage()));
> deadLetterOptions.setDeadLetterErrorDescription(Arrays.stream(cause.getStackTrace())
> .map(StackTraceElement::toString)
> .collect(Collectors.joining("\n")));
> {code}
> To be clear, the *content* here is what Azure asks for. The dead-letter queue
> documentation says:
> {quote}We recommend that you include the type of the exception in the
> {{DeadLetterReason}} and the stack trace of the exception in the
> {{DeadLetterDescription}} as it makes it easier to troubleshoot the cause of
> the problem resulting in messages being dead-lettered. It might result in
> some messages exceeding the 256 KB quota limit for the Standard tier of Azure
> Service Bus.{quote}
> So the component follows the recommendation but not the caveat: a full Camel
> stack trace, with error-handler and processor frames, is routinely several
> thousand characters, and {{cause.getMessage()}} is itself unbounded (a
> database error quoting the statement, a validation report). Nothing truncates
> either one, and {{com.azure.messaging.servicebus.models.DeadLetterOptions}}
> does no client-side length validation (checked against
> azure-messaging-servicebus 7.17.16), so the broker is what rejects it -
> landing on problem 1 above.
> h3. Suggested fix
> Bound both fields, keeping the recommended content but capping it, and guard
> the dead-letter call so a rejection is reported through the exception handler
> rather than escaping {{onFailure}}. The head of a stack trace is the useful
> part; the tail is error-handler frames.
> h3. Evidence
> * Verified by reading the component on main: no {{catch}} around
> {{deadLetter}}, neither field bounded.
> * Verified that {{DeadLetterOptions}} has no length validation in the SDK.
> * The 256 KB Standard-tier caveat is quoted from Microsoft's dead-letter
> queue documentation above.
> * *Not* reproduced against a live namespace. The exact payload size at which
> the broker rejects the request has not been measured, and the documentation
> gives a message-size quota rather than a per-field limit.
> h4. Correction to the original description
> The first version of this issue claimed a documented 4096 limit on the
> dead-letter reason and description. That came from the .NET
> {{DeadLetterMessageAsync}} API reference and is *not* corroborated by the
> dead-letter queue page or the Service Bus quotas page, so I am retracting it.
> The documented constraint is the 256 KB message-size quota on the Standard
> tier, quoted above. The unguarded call - the more serious half - is
> unaffected either way, since it is verified in Camel's own code.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)