You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@camel.apache.org by "Guillaume Nodet (Jira)" <ji...@apache.org> on 2026/10/16 15:03:00 UTC
[jira] [Work started] (CAMEL-25694) camel-milo - awaited write/call service failures are reported as success
[ https://issues.apache.org/jira/browse/CAMEL-25694?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Work on CAMEL-25694 started by Guillaume Nodet.
-----------------------------------------------
> 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
> 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
(v8.20.10#820010)