[
https://issues.apache.org/jira/browse/CAMEL-25846?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
shashank updated CAMEL-25846:
-----------------------------
Description:
{{TahuEdgeProducer}} (main 20cdb309f7d0) keeps the {{TahuEdgeClient}} of each
Edge Node in a static map ({{descriptorClients}}, {{computeIfAbsent}} in
{{createClient}}). When the Edge Node producer stops, it shuts its client down
({{TahuEdgeNodeProducer.doStop}}: {{tahuEdgeClient.shutdown()}}), but the
client stays in the map.
A Tahu {{EdgeClient}} cannot run again after {{shutdown()}}: {{shutdown()}}
sets {{stayRunning}} to false, only the constructor sets it to true, and
{{run()}} returns at once when it is false (Tahu 1.0.21, read with javap). When
the route is started again, Camel creates a new producer, whose constructor
takes the shut down client from the map, and {{doStart}} submits it again
({{TahuEdgeClient.startup()}}). The client never connects to the MQTT server
again: the Edge Node stays offline (its NDEATH was the last message), and every
message sent to the endpoint is dropped. {{EdgeClient.publishSparkplugMessage}}
catches the failure and logs {{Failed to publish message on topic=...}} at
ERROR, so the exchange completes without an exception. Device producers of the
same Edge Node, also in routes that were not restarted, keep the old client
too. This lasts until the JVM restarts (the map is static, so a new
CamelContext in the same JVM takes the shut down client as well). A route
restart is enough: stopping and starting the route (JMX, control bus, a route
policy, a supervising route controller).
*Fix*: the Edge Node producer removes its client from the map when it stops
(and shuts down the client's executor), and creates a new client when it
starts. A new client gets the metric maps of the Edge Node and of its Devices
again (a producer keeps its metric map in a static map by descriptor from its
start to its stop, and a producer that starts after its Edge Node got a new
client adds its map to that client; producers to the same endpoint share its
map, which stays while one of them runs), and Device producers take the current
client of their Edge Node when they publish. A Device producer never creates a
client itself in that case.
*Tests*: new {{TahuEdgeProducerRestartTest}} (3 tests) with {{FakeMqttBroker}},
a small in-process MQTT 3.1.1 broker that acknowledges connections,
subscriptions and publishes and records the published topics.
{{edgeNodePublishesAgainAfterTheRouteIsRestarted}}: NBIRTH and one NDATA, stop
and start the route, then a second NBIRTH and NDATA are expected. On main it
fails after 20 seconds (Awaitility): {{ConditionTimeoutException ... not
published; connects: 1, published: [spBv1.0/RestartGroup/NBIRTH/RestartNode,
spBv1.0/RestartGroup/NDATA/RestartNode,
spBv1.0/RestartGroup/DDEATH/RestartNode/D1,
spBv1.0/RestartGroup/NDEATH/RestartNode]}}.
{{deviceOfAnotherRoutePublishesAgainAfterTheEdgeNodeRouteIsRestarted}}: only
the Edge Node route is restarted, and the Device route's DDATA is expected
after the new DBIRTH; fails on main the same way ({{connects: 1}}). Both pass
with the fix.
{{deviceStillBornAfterTheEdgeNodeRestartWhenOneOfTwoProducersOfTheDeviceStopped}}:
two routes to the same Device endpoint, one stopped, then the Edge Node route
restarted; the Device must be born again (second DBIRTH) and publish. It fails
when a stopped producer removes the shared map ({{ConditionTimeoutException ...
not published}}). camel-tahu unit tests with the fix: 10 run, 0 failures (the
IT tests need a container and were not run).
*How it was found*: variant analysis of CAMEL-25838 (pattern: a client or
connection that is shut down or replaced, while state that belongs to it, here
the client in a static map and the Device metric maps, is kept or lost), then
the JUnit tests.
*Affected*: main, camel-4.23.x, camel-4.18.x and camel-4.14.x (the same static
map and shutdown; read, not run; the {{stayRunning}} behaviour was read in Tahu
1.0.21 only).
_Filed with Claude Code on behalf of allthingssecurity._
was:
{{TahuEdgeProducer}} (main 20cdb309f7d0) keeps the {{TahuEdgeClient}} of each
Edge Node in a static map ({{descriptorClients}}, {{computeIfAbsent}} in
{{createClient}}). When the Edge Node producer stops, it shuts its client down
({{TahuEdgeNodeProducer.doStop}}: {{tahuEdgeClient.shutdown()}}), but the
client stays in the map.
A Tahu {{EdgeClient}} cannot run again after {{shutdown()}}: {{shutdown()}}
sets {{stayRunning}} to false, only the constructor sets it to true, and
{{run()}} returns at once when it is false (Tahu 1.0.21, read with javap). When
the route is started again, Camel creates a new producer, whose constructor
takes the shut down client from the map, and {{doStart}} submits it again
({{TahuEdgeClient.startup()}}). The client never connects to the MQTT server
again: the Edge Node stays offline (its NDEATH was the last message), and every
message sent to the endpoint is dropped. {{EdgeClient.publishSparkplugMessage}}
catches the failure and logs {{Failed to publish message on topic=...}} at
ERROR, so the exchange completes without an exception. Device producers of the
same Edge Node, also in routes that were not restarted, keep the old client
too. This lasts until the JVM restarts (the map is static, so a new
CamelContext in the same JVM takes the shut down client as well). A route
restart is enough: stopping and starting the route (JMX, control bus, a route
policy, a supervising route controller).
*Fix*: the Edge Node producer removes its client from the map when it stops
(and shuts down the client's executor), and creates a new client when it
starts. A new client gets the metric maps of the Edge Node and of its Devices
again (a producer keeps its metric map in a static map by descriptor from its
start to its stop, and a producer that starts after its Edge Node got a new
client adds its map to that client), and Device producers take the current
client of their Edge Node when they publish. A Device producer never creates a
client itself in that case.
*Tests*: new {{TahuEdgeProducerRestartTest}} (2 tests) with {{FakeMqttBroker}},
a small in-process MQTT 3.1.1 broker that acknowledges connections,
subscriptions and publishes and records the published topics.
{{edgeNodePublishesAgainAfterTheRouteIsRestarted}}: NBIRTH and one NDATA, stop
and start the route, then a second NBIRTH and NDATA are expected. On main it
fails after 20 seconds (Awaitility): {{ConditionTimeoutException ... not
published; connects: 1, published: [spBv1.0/RestartGroup/NBIRTH/RestartNode,
spBv1.0/RestartGroup/NDATA/RestartNode,
spBv1.0/RestartGroup/DDEATH/RestartNode/D1,
spBv1.0/RestartGroup/NDEATH/RestartNode]}}.
{{deviceOfAnotherRoutePublishesAgainAfterTheEdgeNodeRouteIsRestarted}}: only
the Edge Node route is restarted, and the Device route's DDATA is expected
after the new DBIRTH; fails on main the same way ({{connects: 1}}). Both pass
with the fix. camel-tahu unit tests with the fix: 9 run, 0 failures (the IT
tests need a container and were not run).
*How it was found*: variant analysis of CAMEL-25838 (pattern: a client or
connection that is shut down or replaced, while state that belongs to it, here
the client in a static map and the Device metric maps, is kept or lost), then
the JUnit tests.
*Affected*: main, camel-4.23.x, camel-4.18.x and camel-4.14.x (the same static
map and shutdown; read, not run; the {{stayRunning}} behaviour was read in Tahu
1.0.21 only).
_Filed with Claude Code on behalf of allthingssecurity._
> camel-tahu - after its route is restarted, an Edge Node producer never
> connects again and drops every message (logged, the exchange completes)
> ----------------------------------------------------------------------------------------------------------------------------------------------
>
> Key: CAMEL-25846
> URL: https://issues.apache.org/jira/browse/CAMEL-25846
> Project: Camel
> Issue Type: Bug
> Components: camel-tahu
> Reporter: shashank
> Assignee: shashank
> Priority: Major
>
> {{TahuEdgeProducer}} (main 20cdb309f7d0) keeps the {{TahuEdgeClient}} of each
> Edge Node in a static map ({{descriptorClients}}, {{computeIfAbsent}} in
> {{createClient}}). When the Edge Node producer stops, it shuts its client
> down ({{TahuEdgeNodeProducer.doStop}}: {{tahuEdgeClient.shutdown()}}), but
> the client stays in the map.
> A Tahu {{EdgeClient}} cannot run again after {{shutdown()}}: {{shutdown()}}
> sets {{stayRunning}} to false, only the constructor sets it to true, and
> {{run()}} returns at once when it is false (Tahu 1.0.21, read with javap).
> When the route is started again, Camel creates a new producer, whose
> constructor takes the shut down client from the map, and {{doStart}} submits
> it again ({{TahuEdgeClient.startup()}}). The client never connects to the
> MQTT server again: the Edge Node stays offline (its NDEATH was the last
> message), and every message sent to the endpoint is dropped.
> {{EdgeClient.publishSparkplugMessage}} catches the failure and logs {{Failed
> to publish message on topic=...}} at ERROR, so the exchange completes without
> an exception. Device producers of the same Edge Node, also in routes that
> were not restarted, keep the old client too. This lasts until the JVM
> restarts (the map is static, so a new CamelContext in the same JVM takes the
> shut down client as well). A route restart is enough: stopping and starting
> the route (JMX, control bus, a route policy, a supervising route controller).
> *Fix*: the Edge Node producer removes its client from the map when it stops
> (and shuts down the client's executor), and creates a new client when it
> starts. A new client gets the metric maps of the Edge Node and of its Devices
> again (a producer keeps its metric map in a static map by descriptor from its
> start to its stop, and a producer that starts after its Edge Node got a new
> client adds its map to that client; producers to the same endpoint share its
> map, which stays while one of them runs), and Device producers take the
> current client of their Edge Node when they publish. A Device producer never
> creates a client itself in that case.
> *Tests*: new {{TahuEdgeProducerRestartTest}} (3 tests) with
> {{FakeMqttBroker}}, a small in-process MQTT 3.1.1 broker that acknowledges
> connections, subscriptions and publishes and records the published topics.
> {{edgeNodePublishesAgainAfterTheRouteIsRestarted}}: NBIRTH and one NDATA,
> stop and start the route, then a second NBIRTH and NDATA are expected. On
> main it fails after 20 seconds (Awaitility): {{ConditionTimeoutException ...
> not published; connects: 1, published:
> [spBv1.0/RestartGroup/NBIRTH/RestartNode,
> spBv1.0/RestartGroup/NDATA/RestartNode,
> spBv1.0/RestartGroup/DDEATH/RestartNode/D1,
> spBv1.0/RestartGroup/NDEATH/RestartNode]}}.
> {{deviceOfAnotherRoutePublishesAgainAfterTheEdgeNodeRouteIsRestarted}}: only
> the Edge Node route is restarted, and the Device route's DDATA is expected
> after the new DBIRTH; fails on main the same way ({{connects: 1}}). Both pass
> with the fix.
> {{deviceStillBornAfterTheEdgeNodeRestartWhenOneOfTwoProducersOfTheDeviceStopped}}:
> two routes to the same Device endpoint, one stopped, then the Edge Node
> route restarted; the Device must be born again (second DBIRTH) and publish.
> It fails when a stopped producer removes the shared map
> ({{ConditionTimeoutException ... not published}}). camel-tahu unit tests with
> the fix: 10 run, 0 failures (the IT tests need a container and were not run).
> *How it was found*: variant analysis of CAMEL-25838 (pattern: a client or
> connection that is shut down or replaced, while state that belongs to it,
> here the client in a static map and the Device metric maps, is kept or lost),
> then the JUnit tests.
> *Affected*: main, camel-4.23.x, camel-4.18.x and camel-4.14.x (the same
> static map and shutdown; read, not run; the {{stayRunning}} behaviour was
> read in Tahu 1.0.21 only).
> _Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)