Claus Ibsen created CAMEL-26663:
-----------------------------------
Summary: camel-hazelcast - HazelcastAggregationRepository
optimistic remove() can lose a completed group
Key: CAMEL-26663
URL: https://issues.apache.org/jira/browse/CAMEL-26663
Project: Camel
Issue Type: Bug
Components: camel-hazelcast
Reporter: Claus Ibsen
This has the same flaw as CAMEL-26395 (camel-redis).
In {{HazelcastAggregationRepository.remove()}} with {{optimistic=true}} and
{{useRecovery=true}}, the group is removed from the active map first
({{cache.remove(key, holder)}}). Only afterwards is it written to the recovery
map ({{persistedCache.put(exchangeId, holder)}}). If the JVM crashes between
the two calls, or the {{put}} throws, the completed group is in neither map and
is lost.
The pessimistic branch does not have this problem, because it runs both steps
in a Hazelcast transaction.
Suggested fix, the same as the one proposed on CAMEL-26395:
# When {{useRecovery}} is true, put the exchange in the recovery map first.
# Then call {{cache.remove(key, holder)}}.
# If the remove fails, remove the staged entry from the recovery map and throw
{{OptimisticLockingException}}. If that cleanup fails too, log a WARN with the
cause and still throw {{OptimisticLockingException}}.
In the worst case a group is then sent twice instead of being lost. On the same
node, the recover task cannot pick up the staged entry early:
{{AggregateProcessor}} marks the exchange as completing before it calls
{{remove()}}, and the recover task skips those exchanges. Another Camel node
does not see that mark, so it could briefly recover a staged entry whose remove
then fails. The PR should mention this.
Tests to add:
* The recovery {{put}} fails: {{remove()}} throws, and the group is still in
the active map.
* A remove with a stale holder throws {{OptimisticLockingException}} and leaves
nothing in the recovery map.
_Claude Code on behalf of davsclaus_
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)