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)