[
https://issues.apache.org/jira/browse/CAMEL-25694?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Claus Ibsen updated CAMEL-25694:
--------------------------------
Fix Version/s: 4.18.6
4.22.3
> camel-milo - awaited write/call service failures are reported as success
> ------------------------------------------------------------------------
>
> Key: CAMEL-25694
> URL: https://issues.apache.org/jira/browse/CAMEL-25694
> Project: Camel
> Issue Type: Bug
> Components: camel-milo
> Affects Versions: 4.22.1
> Environment: Camel 4.22.1, Eclipse Milo 1.1.6, OpenJDK 25.0.4, Maven
> 3.9.16; macOS arm64. Real loopback OPC UA test servers: Milo (attached
> reproducer) and independent asyncua 1.1.8 / Python 3.12 with a TCP relay.
> Also reproduced using compiled camel-milo source at
> 9c6d4cfc2164f36f2f2b10eb4e09b8956e2925d9 with cached 4.24.0-SNAPSHOT
> dependencies. No physical PLC or production deployment was used.
> Reporter: Serdar Gökay
> Assignee: Guillaume Nodet
> Priority: Major
> Fix For: 4.18.6, 4.22.3, 4.24.0
>
> Attachments: camel-milo-awaited-failure-reproducer.zip
>
>
> h3. Problem
> An awaited milo-client write can fail at the OPC UA service/transport layer
> while the Camel exchange completes successfully with a null body. The success
> continuation runs and configured redelivery, onException and dead-letter
> handling are skipped.
> Reproduced on released Camel 4.22.1 / Eclipse Milo 1.1.6 with a real TCP OPC
> UA server and a separate OPC UA readback client. The same failure was
> reproduced with the camel-milo source compiled at
> 9c6d4cfc2164f36f2f2b10eb4e09b8956e2925d9 (4.24.0-SNAPSHOT, PR #27910
> revision). This predates the subscription watchdog work.
> Awaiting is enabled with message header {{CamelMiloAwait=true}} or endpoint
> option {{defaultAwaitWrites=true}}. Both reproduce the issue.
> h3. Reproduction
> The attached standalone Maven project starts its own loopback TCP OPC UA
> server. It does not mock a client, connection, future or transport, and does
> not patch Camel classes.
> {code:bash}
> mvn -B -ntp test -Dtest=AwaitedWriteContractTest
> {code}
> # Establish the connection and successfully write 41; assert a Good
> StatusCode and independent readback of 41.
> # Ask Camel to write 99. The real server responds with a Bad_Timeout
> ServiceFault before applying the write.
> # Read the node through the independent client: it is still 41.
> # Inspect the Camel exchange and route counters:
> {noformat}
> attempted=99 readback=41 serverValue=41
> writes=1 redeliveries=0 downstream=1
> failed=false exception=null body=null
> {noformat}
> The test requires the service failure to reach the exchange and fails for
> that assertion on 4.22.1. The native Milo client against the same
> server/fault throws UaException with the matching status.
> The attachment also contains 15 behavior/control tests ({{mvn test
> '-Dtest=*EvidenceTest'}}). These intentionally characterize current behavior,
> including the defect; passing them does not mean the bug is fixed. They cover
> both await settings, Bad_Timeout and Bad_SessionClosed service faults, normal
> bad per-node status, retry/DLQ/onException controls, method calls and gated
> fire-and-forget behavior. Bad_SessionClosed is a controlled service-fault
> response rather than an actual session-expiry simulation.
> An independent asyncua server behind a TCP relay also reproduced the failure
> when request traffic was dropped or an established connection was closed.
> Readback remained unchanged while Camel continued successfully. Dropping only
> the reply instead allowed the write to apply, but Camel still incorrectly
> returned a successful null result. These are distinct outcome cases.
> h3. Expected behavior
> When the awaited operation completes exceptionally, preserve that exceptional
> completion so MiloClientProducer fails the exchange and Camel error handling
> can run. Preserve existing successful write StatusCode results, ordinary
> per-node bad StatusCode results, and explicitly non-awaited behavior.
> An already-disconnected manager has a separate exceptional {{No connected}}
> path. Merely starting against an absent server can miss this defect; the
> reproduction first establishes a working connection.
> h3. Cause and proposed direction
> In {{SubscriptionManager.write}}, {{handleAsync}} calls
> {{handleConnectionFailure(error)}} and then returns {{status}}, which is null
> after exceptional completion. That converts the failed future into normal
> completion. {{MiloClientProducer}} already sets the exchange exception when
> it receives an exceptional future.
> Proposed write change, retaining the executor and recovery callback:
> {code:java}
> return this.connected.write(nodeId, value).whenCompleteAsync((status, error)
> -> {
> if (error != null) {
> handleConnectionFailure(error);
> }
> }, this.executor);
> {code}
> This is a proposed direction, not an applied or verified fix. Preserve
> asynchronous dispatch and recovery behavior. The result/exception should
> remain the source future's completion.
> {{call}} has the same failure-propagation defect, also reproduced. It
> additionally returns null even on success. Changing to {{whenCompleteAsync}}
> would expose successful CallMethodResult bodies too; either explicitly cover
> that restoration or retain the historical success-null result after
> preserving completion. Ordinary bad per-node write statuses remain a separate
> status-as-body contract, as introduced by CAMEL-18618.
> Propagating a timeout restores error handling; it does not prove that the
> device did not act or make arbitrary command retries exactly-once.
> Read/browse have similar handlers but were outside this reproduction's scope.
> Pinned released source: [SubscriptionManager
> write/call|https://github.com/apache/camel/blob/c056bef67cdfeffdc0ad7255e5e052cab71f2921/components/camel-milo/src/main/java/org/apache/camel/component/milo/client/internal/SubscriptionManager.java#L971-L1012]
> and
> [MiloClientProducer|https://github.com/apache/camel/blob/c056bef67cdfeffdc0ad7255e5e052cab71f2921/components/camel-milo/src/main/java/org/apache/camel/component/milo/client/MiloClientProducer.java#L91-L100].
> _Report and reproduction prepared with Codex on behalf of GitHub user
> etzel-mes._
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)