gnodet opened a new pull request, #27956:
URL: https://github.com/apache/camel/pull/27956

   ## Summary
   
   Fix OPC-UA write/call/readValues/browse service failures being silently 
swallowed and reported as success when using the awaited 
(`CamelMiloAwait=true`) mode.
   
   ## Root Cause
   
   `SubscriptionManager.write()`, `call()`, `readValues()`, and `browse()` all 
chained the underlying Milo client future with `handleAsync()`:
   
   ```java
   return this.connected.write(nodeId, value).handleAsync((status, e) -> {
       if (e != null) {
           handleConnectionFailure(e);
       }
       return status;   // returns null when e != null
   }, this.executor);
   ```
   
   When the OPC-UA operation fails (e.g. `Bad_Timeout` service fault), 
`handleAsync` receives a non-null exception. It calls 
`handleConnectionFailure(e)` for the reconnection side-effect, then **returns 
the value (null)**, converting the exceptional completion into a normal null 
completion.
   
   `MiloClientProducer` awaits the returned future and only propagates errors 
when the throwable is non-null:
   
   ```java
   future.whenComplete((result, throwable) -> {
       if (throwable != null) exchange.setException(throwable);
       else msg.setBody(result);   // sets null body → reports success
   });
   ```
   
   Since `handleAsync` had already discarded the exception, the producer saw a 
null-completed future, set the body to `null`, and reported success. No error 
was raised to the Camel route.
   
   ## Fix
   
   Replace `handleAsync()` with `whenCompleteAsync()` in all four methods. 
`whenCompleteAsync` runs the side-effect (reconnection) but propagates the 
original completion unchanged — exceptions stay exceptional, successes stay 
successful:
   
   ```java
   return this.connected.write(nodeId, value).whenCompleteAsync((status, e) -> {
       // handle outside the lock, running using
       // whenCompleteAsync (preserves the original exceptional completion)
       if (e != null) {
           handleConnectionFailure(e);
       }
   }, this.executor);
   ```
   
   ## Tests
   
   Two new test classes:
   
   - **`MiloClientProducerWriteFailureTest`**: tests that `MiloClientProducer` 
correctly propagates awaited write/call failures as exchange exceptions, and 
that non-awaited (fire-and-forget) writes do not set exceptions. Uses a 
`MiloClientConnection` stub returning pre-arranged futures.
   
   - **`SubscriptionManagerExceptionPropagationTest`**: tests the 
`whenCompleteAsync`-vs-`handleAsync` future completion contract directly (no 
server needed), and verifies that disconnected managers return exceptional 
futures from `write()`, `call()`, and `readValues()`.
   
   Fixes https://issues.apache.org/jira/browse/CAMEL-25694
   
   _Hermes Agent (Claude Sonnet 4.6) on behalf of Guillaume Nodet_
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to