Serdar Gökay created CAMEL-25835:
------------------------------------

             Summary: camel-milo - the consumer reports a lost connection and 
refreshes its values after it
                 Key: CAMEL-25835
                 URL: https://issues.apache.org/jira/browse/CAMEL-25835
             Project: Camel
          Issue Type: Improvement
          Components: camel-milo
            Reporter: Serdar Gökay


h3. Problem

The milo-client consumer hands every data change notification to its route and 
reports nothing when the values stop:

* When the session drops and Milo activates it again, the consumer only flips 
its {{sessionActive}} flag. The route sees a pause, and the values that did not 
change during the outage are not delivered again afterwards.
* When the subscription is transferred to a new session, or when camel-milo 
rebuilds the connection (a failed transfer, a rejected CreateMonitoredItems, a 
failed producer request), the route sees a pause and then the first values of 
the new subscription.
* When the server cannot be reached at startup, or the client cannot connect at 
all (wrong credentials, an untrusted server certificate), the route sees 
nothing until the server is reachable.

A route cannot tell "unchanged" from "unknown": a historian keeps the last 
value, a publisher republishes it as live, an alarm stays quiet. Products in 
camel-milo's place mark every item when the source is lost and refresh the 
values after recovery (for example the Kepware IoT Gateway, WinCC OA's 
invalid-on-connection-loss setting, Sparkplug's STALE on NDEATH/DDEATH), and 
the OPC UA specifications say how.

h3. Proposal

*Signal.* When communication with the server is lost, every monitored node 
delivers one exchange whose {{DataValue}} has a null value and the status 
{{Bad_NoCommunication}} (0x80310000), with SourceTimestamp and ServerTimestamp 
set to the time camel-milo recognised the loss. A node is reported once per 
loss: a node whose last delivery is already the report gets no second one, and 
a node whose monitored item the server refused keeps that status (its state 
does not depend on the communication).

*When.* The session stops being active (Milo's {{SessionActivityListener}}); 
camel-milo rebuilds the connection ({{handleConnectionFailure}}); nodes are 
registered while there is no connection or the session is not active.

*Refresh.* When the same session is activated again, camel-milo calls the 
server's {{ResendData}} method for its subscription (OPC 10000-5 §9.2), so the 
server sends the current value of every monitored node in the next Publish 
responses, the unchanged ones included. When the call fails for any reason 
other than a lost session, camel-milo deletes the subscription and creates it 
again in the session, with the recovery of CAMEL-25691; the new items deliver 
their first values. After a transfer or a rebuild the server sends the first 
values anyway, so nothing more is done there.

*Order.* Within one connection, reports and values arrive in order on the 
subscription's delivery queue: the report lands after the values the queue 
still holds and before the values of the activated session. A value that a 
replaced connection still delivers can arrive after the new connection's first 
value, as today. The contract is arrival order, and the documentation says so.

*Not done.* No value cache, no option, no debounce, no marker header, no read 
fallback for servers without ResendData (every open-source server stack I read 
implements it: Milo, open62541, node-opcua, the OPC Foundation .NET stack), no 
handling of lost notifications, no per-node ordering rules. Event items are 
unchanged.

h3. Standard

|| Topic || Rule || Source ||
| Status for a lost source | {{Bad_NoCommunication}}: communication with the 
data source is defined but not established, and no last known value is 
available | OPC 10000-4 §7.38 Table 179; OPC 10000-8 §7.3 Table 61 |
| Null value | An error status means a null value | OPC 10000-4 §7.11 Table 131 
|
| Timestamps of a Bad value | SourceTimestamp may be the time the component 
became aware of the status | OPC 10000-4 §7.11.3 alternative (a) |
| Consumer of a lost source | Without value handling, a reader in Error writes 
null with {{Bad_NoCommunication}} | OPC 10000-14 §6.2.11.1 Table 80 |
| Refresh after lost notifications | ResendData, or a read of the current value 
of every data item | OPC 10000-4 §6.7 step 6 |
| ResendData | {{ResendData(UInt32 subscriptionId)}} on the Server object: the 
next Publish responses carry the current value of every Reporting data item | 
OPC 10000-5 §9.2 |

camel-milo keeps no value, so Table 80's row without value handling applies: 
null with {{Bad_NoCommunication}}.

h3. Behaviour change for routes

* A route that uses only the value of the body receives a null for these 
exchanges, which the type converters turn into {{0}} or {{false}}; a route that 
stores values checks {{${body.statusCode.bad}}} first.
* A value can arrive again after an outage, so a route that counts values or 
detects changes must tolerate repeats.
* Clients that cannot connect at all now deliver the status for their nodes, 
with the cause in the log; a connection that camel-milo rebuilds after a failed 
request delivers it for every node of the connection.
* The consumer's route also runs during an outage; a write it makes while the 
client reconnects waits for the next reconnect attempt and can take effect late.

h3. Verification

Implemented and tested: a new test with a TCP relay between the client and the 
embedded Milo server (two losses in a row on the same session, the unchanged 
value resent, a change in between delivered, a refused node kept its own 
status, a consumer started with the relay down), three existing tests updated 
to the new behaviour, and runs against a real server that is not built on Milo 
(Microsoft opc-plc 2.15.4): a 20 s silent drop with and without writes, a 150 s 
drop, a server restart, a value queued behind a slow route, a consumer started 
while the server was stopped, a refused node. One {{Bad_NoCommunication}} per 
node per outage in every run; ResendData answered Good on the same session, 
10-14 s detection of a silent drop with Milo's keep-alive defaults, rebuild 
after the long drop and the restart.

Relation to CAMEL-25692: that improvement changes the registration code too; 
whichever lands second will be rebased.

PR to follow.

_Claude Code on behalf of etzel-mes_



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to