shashank created CAMEL-25947:
--------------------------------
Summary: camel-spring-rabbitmq - with confirm=auto the producer
does not wait for publisher confirms of type SIMPLE, so a message RabbitMQ
negatively acknowledges or does not confirm is lost without an error
Key: CAMEL-25947
URL: https://issues.apache.org/jira/browse/CAMEL-25947
Project: Camel
Issue Type: Bug
Components: camel-spring-rabbitmq
Reporter: shashank
Assignee: shashank
With the default {{confirm=auto}}, the InOnly producer
({{SpringRabbitMQProducer.processInOnly}}, main 9f839f4bcc9d) decides whether
to wait for publisher confirms with
{{getConnectionFactory().isPublisherConfirms()}}. In spring-rabbit 4.1.1,
{{CachingConnectionFactory.isPublisherConfirms()}} is
{{ConfirmType.CORRELATED.equals(confirmType)}}. A connection factory with
publisher confirms of type {{SIMPLE}} answers {{isSimplePublisherConfirms()}}
instead (javap of both methods), and {{SIMPLE}} is the type that
{{RabbitTemplate.invoke}} plus {{waitForConfirms}} is meant for. So with
{{spring.rabbitmq.publisher-confirm-type=simple}}, or
{{setPublisherConfirmType(ConfirmType.SIMPLE)}}, the producer:
* puts the channel in confirm mode (the connection factory does that) but never
waits for the confirm;
* completes the exchange as soon as {{basicPublish}} returns. A message that
RabbitMQ negatively acknowledges (for example a full queue with
{{x-overflow=reject-publish}}), or never confirms (a broker that goes down
before the message is written), is lost without an error. That is what
publisher confirms were configured to prevent, and the option documentation
says "auto = Camel detects if the connection factory uses confirms or not".
*Fix*: {{confirm=auto}} waits when the connection factory has publisher
confirms of either type ({{isPublisherConfirms() ||
isSimplePublisherConfirms()}}). {{RabbitTemplate.waitForConfirms(long)}}
returns {{false}} only for a negative acknowledgement, so the
{{TimeoutException}} of that case now says "Message negatively acknowledged by
RabbitMQ". When no confirm arrives within {{confirmTimeout}}, amqp-client
5.31.0 {{ChannelN.waitForConfirms}} throws
{{java.util.concurrent.TimeoutException}}, which {{RabbitTemplate}} turns into
an {{AmqpTimeoutException}} (javap of both); that fails the exchange. Upgrade
guide entry: such producers now wait up to {{confirmTimeout}} per message and
fail on a negative acknowledgement or a missing confirm; {{confirm=disabled}}
keeps the old behaviour.
*Tests*: new {{SpringRabbitMQProducerConfirmTest}}. It uses a real
{{CachingConnectionFactory}} over a mocked RabbitMQ client. The mocked
{{Channel.waitForConfirms(long)}} answers as the client documents: {{true}}
when everything was acked, {{false}} when a message was nacked, and a
{{TimeoutException}} when the timeout elapses. Three tests fail on main:
* {{negativeAcknowledgementFailsTheExchangeWithSimplePublisherConfirms}}:
{{expected: <java.util.concurrent.TimeoutException> but was: <null>}};
* {{missingConfirmFailsTheExchangeWithSimplePublisherConfirms}}: {{expected:
<org.springframework.amqp.AmqpTimeoutException> but was: <null>}};
* {{acknowledgedMessageIsSentWithSimplePublisherConfirms}}: {{Wanted but not
invoked: channel.waitForConfirms(5000L)}}.
Two controls pass on main and with the fix: {{CORRELATED}} still waits, and no
confirms means no wait.
camel-spring-rabbitmq unit tests with the fix: 11 run, 0 failures.
*How it was found*: library-contract mining. I read which {{ConnectionFactory}}
method reports which confirm type in spring-rabbit 4.1.1, and checked the
producer's {{auto}} detection against it.
*Affected*: main, camel-4.23.x, camel-4.22.x, camel-4.18.x and camel-4.14.x
(the same {{isPublisherConfirms()}} check). I read the code on those branches
but did not run the tests there.
_Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)