etzel-mes opened a new pull request, #28371: URL: https://github.com/apache/camel/pull/28371
# Description Raised in the review of #28212 and filed as CAMEL-25912. `SubscriptionManager` used one lock for the subscription work and for the producer requests. Registering and deleting monitored items, recreating a subscription and the retry of refused nodes (CAMEL-25692) hold that lock across a blocking service call; `write`, `call`, `readValues`, `browse` and `getOpcUaClient()` took the same lock only to read the current connection and start an asynchronous request. A setpoint write therefore waited for unrelated subscription work on the same connection: one round trip normally, about 10 s during a silent network drop (until the keep-alive declared the session lost), up to `requestTimeout` when the server answered keep-alives but not the call. With one processor the outcome of a producer request also waited for the refused-node retry, which ran its blocking call on the single-thread `MiloClient` executor that completes the producer requests. What changes: - The producers and `getOpcUaClient()` read the current connection without the lock. `Connected.client` is final, so a request on a connection disposed meanwhile fails with Milo's own `UaException` (`Bad_SessionClosed`, or `Bad_ConnectionClosed` for one in flight) instead of a `NullPointerException`. `handleConnectionFailure()` and `dispose()` clear the current connection before they disconnect it, so `getOpcUaClient()` keeps returning `null` while there is no usable connection. - A failed producer request no longer disconnects the client and rebuilds the subscriptions of the consumers that share the connection. The exchange gets the failure (CAMEL-25694); a lost session is recovered by the client, a session the server no longer has fails the subscription transfer, which rebuilds the connection, and the watchdog (CAMEL-25691) handles a subscription that stops publishing. This is the decision CAMEL-25692 already took for the retry. The outcome is still completed on the `MiloClient` executor, so a route never continues on a Milo thread (CAMEL-25713). - The retry of refused nodes runs its attempt on the `MiloClientReconnect` thread instead of the `MiloClient` executor. A rebuild needs the lock, which the attempt holds until the server answers, so it does not wait longer than before. - Unchanged: the synchronous not-connected result with `lastConnectFailure` as its cause; consumer-side failures still rebuild the connection; the subscription work keeps the lock and its ordering. Behaviour change, documented on the component page and in the 4.24 upgrade guide: a failed write, call, read or browse keeps the connection (no `Bad_NoCommunication` report to the consumers, same session); producer requests and `getOpcUaClient()` no longer wait for a consumer that starts or stops or for the retry; while Camel rebuilds the connection a producer request fails at once instead of waiting for the rebuild. Two sentences of the CAMEL-25835 note that said a failed request rebuilds the connection are corrected. Three follow-ups are named in the commit message: the disconnect in `handleConnectionFailure()` still runs under the lock; endpoint discovery and a renewed server certificate are now recovered only by a Camel rebuild (as for consumer-only connections since CAMEL-25691); `onTransferFailed` has no identity check. Tests: new `ProducerOnSharedConnectionTest` (4 tests on the embedded server and the TCP relay, which gains `silence()`): a producer and `getOpcUaClient()` return within 2 s while a consumer start waits under the lock on a silent link; a write that times out keeps the connection; a write on a replaced connection fails with `Bad_ConnectionClosed` and keeps the replacement; a write completes within 2 s while the retry stalls on a single-thread executor. Each fails on the unmodified code for the stated reason. No existing assertion pinned the old teardown. Module `-Psourcecheck verify` with `-Dsurefire.rerunFailingTestsCount=0`: 125 tests, 0 failures, 1 skipped (as upstream). Measured on a real server (opc-plc 2.15.4 and node-opcua, client with `--cpus=1`, two runs each): | scenario | before | after | |---|---|---| | refused-node retry in flight, 30 s silent drop: write / read / `getOpcUaClient()` wait on the lock | 9–10 s / 14–15 s / 15–16 s | none | | the same: connection torn down after the drop | every run, one `Bad_NoCommunication` per consumer | none, the client reactivates the same session 0.1–0.9 s after the drop ends | | producer failure alone, 30 s drop: connection torn down | every run | none; writes resume 0.3–1.0 s after the drop ends (before 4.6–5.5 s) | | server answers keep-alives but holds CreateMonitoredItems 30 s / 70 s: write | 29 s / 60 s | 19–120 ms | Fixes CAMEL-25912. @davsclaus @oscerd # Target - [x] I checked that the commit is targeting the correct branch (Camel 4 uses the `main` branch) # Tracking - [x] If this is a large change, bug fix, or code improvement, I checked there is a [JIRA issue](https://issues.apache.org/jira/browse/CAMEL) filed for the change (usually before you start working on it). # Apache Camel coding standards and style - [x] I checked that each commit in the pull request has a meaningful subject line and body. - [ ] I have run `mvn clean install -DskipTests` locally from root folder and I have committed all auto-generated changes. # AI-assisted contributions - [x] If this PR includes AI-generated code, commits have proper co-authorship attribution (e.g., `Co-authored-by` trailers) and the PR description identifies the AI tool used. _Claude Code on behalf of etzel-mes_ -- 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]
