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)

Reply via email to