Andrea Cosentino created CAMEL-26488:
----------------------------------------
Summary: camel-mina - sync producer always closes a timed-out
session
Key: CAMEL-26488
URL: https://issues.apache.org/jira/browse/CAMEL-26488
Project: Camel
Issue Type: Bug
Components: camel-mina
Reporter: Andrea Cosentino
Assignee: Andrea Cosentino
Fix For: 4.24.0
The camel-mina synchronous producer ({{MinaProducer}} with {{sync=true}})
writes a request to the MINA {{IoSession}} and then waits on a per-exchange
{{CountDownLatch}} ({{responseLatch}}) for the reply. A single inner
{{ResponseHandler}} ({{IoHandlerAdapter}}) stores the latest inbound message in
a field and counts down whichever {{responseLatch}} is current
({{messageReceived}} then {{notifyResultAvailable}}). A sync producer is
non-singleton ({{isSingleton()}} returns false when sync is enabled), so it is
pooled and reused across exchanges.
h3. Current behaviour
When an exchange does not receive a reply within {{timeout}}, {{doProcess}}
calls {{maybeDisconnectOnTimeout()}} and throws {{ExchangeTimedOutException}}.
{{maybeDisconnectOnTimeout()}} currently closes the session only when
{{disconnectOnNoReply=true}} (the default).
With {{disconnectOnNoReply=false}} a timed-out session is left open and
connected. Because the producer is pooled and reused, the next exchange
acquires the same producer, finds the session still open in {{doProcess}}, and
writes on it without reopening. If the peer then delivers the reply belonging
to the earlier (already timed-out) request, the shared
{{ResponseHandler.messageReceived}} stores that message and counts down the
current exchange's latch. The later exchange therefore completes successfully
with a message that was produced for the earlier request: there is no
correlation between an inbound reply and the request that is currently waiting.
The {{disconnectOnNoReply}} option is documented for the consumer only. The
{{MinaConfiguration.setDisconnectOnNoReply}} javadoc reads "If sync is enabled
then this option dictates MinaConsumer if it should disconnect where there is
no reply to send back." The producer honours the option as well, and nothing
documents that keeping a producer session open after a timeout lets a stale
reply be applied to a later exchange.
h3. Behaviour after the change
A synchronous producer always closes its session when a request times out,
regardless of {{disconnectOnNoReply}}, so a session whose peer still owes a
reply is never reused by a later exchange. The next exchange finds a closed
session and opens a fresh connection. The default behaviour
({{disconnectOnNoReply=true}}) is unchanged.
As a second layer, the {{ResponseHandler}} applies an inbound message to the
waiting exchange only when a matching request is actually in flight; a message
that arrives while no request is waiting, or that belongs to an earlier
request, is discarded instead of being returned as the current exchange's
result.
h3. Classes involved
*
{{components/camel-mina/src/main/java/org/apache/camel/component/mina/MinaProducer.java}}
- {{doProcess}}, {{maybeDisconnectOnTimeout()}} and the inner
{{ResponseHandler}}.
*
{{components/camel-mina/src/main/java/org/apache/camel/component/mina/MinaConfiguration.java}}
- the {{setDisconnectOnNoReply}} javadoc.
h3. Code-level change
* {{maybeDisconnectOnTimeout()}} closes the producer session on timeout
unconditionally; previously it closed only when {{disconnectOnNoReply}} was
{{true}}. This continues the direction of CAMEL-17022, which introduced
{{maybeDisconnectOnTimeout()}}, and must not be reverted.
* {{ResponseHandler}} gains an in-flight request guard (a request generation
set in {{doProcess}} before the write and captured by the handler) so
{{messageReceived}} applies a reply to the current exchange only when it
matches the waiting request, and otherwise discards it.
* The {{MinaConfiguration.setDisconnectOnNoReply}} javadoc is updated to state
that the producer also uses the option and that a timed-out producer session is
now closed regardless of its value. Regenerate the catalog, component-DSL and
endpoint-DSL mirrors and {{mina-component.adoc}} if any option metadata or
description changes.
* A functional note is added to
{{docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc}} on
{{main}} describing the changed producer-on-timeout behaviour.
h3. Tests
A new regression test under
{{components/camel-mina/src/test/java/org/apache/camel/component/mina/}}
(modelled on {{MinaDisconnectOnTimeOutTest}}): a sync producer with
{{disconnectOnNoReply=false}} runs two sequential InOut exchanges against a
test MINA TCP server that delays the first reply until the second request is in
flight (coordinated with latches, no {{Thread.sleep}}, using {{MockEndpoint}}
timed assertions or Awaitility per project conventions). The test asserts that
the second exchange does not complete with the first exchange's reply - it
either times out or receives only its own reply. The existing
{{MinaDisconnectOnTimeOutTest}} and the concurrent producer tests remain green.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)