[
https://issues.apache.org/jira/browse/CAMEL-26488?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Work on CAMEL-26488 started by Andrea Cosentino.
------------------------------------------------
> 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
> Priority: Major
> 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)