shashank created CAMEL-25543:
--------------------------------
Summary: camel-dapr - the saveBulk and executeTransaction state
operations never send their request to Dapr, so nothing is stored and the
exchange completes without an error
Key: CAMEL-25543
URL: https://issues.apache.org/jira/browse/CAMEL-25543
Project: Camel
Issue Type: Bug
Components: camel-dapr
Reporter: shashank
Assignee: shashank
{{DaprClient}} returns a Reactor {{Mono}} for every request, and the request is
sent when the {{Mono}} is subscribed to. {{DaprStateHandler}} (at main
9432ba16d026) blocks on it for {{save}} (line 78), {{get}}, {{getBulk}} and
{{delete}} (line 135), but drops it for the two other operations:
{code:java}
private DaprOperationResponse saveBulkState(Exchange exchange, DaprClient
client) {
...
client.saveBulkState(stateRequest); // line 90: the Mono is
never subscribed to
return DaprOperationResponse.create(stateRequest);
}
private DaprOperationResponse executeStateTransaction(Exchange exchange,
DaprClient client) {
...
client.executeStateTransaction(stateRequest); // line 149: the same
return DaprOperationResponse.create(stateRequest);
}
{code}
So {{dapr:state?stateOperation=saveBulk}} and
{{dapr:state?stateOperation=executeTransaction}} do nothing: no request reaches
the sidecar, no state is stored, updated or deleted, and the exchange completes
successfully with the request object as the body. Nothing is logged. The
component documentation describes both operations ("Store or update multiple
key-value pairs in the state store in a single operation", "Execute a batch of
operations (save or delete) atomically within a transaction").
A probe with the real Dapr client and no sidecar shows the behaviour of the
{{Mono}}: {{client.saveBulkState(request)}} returns without an error, and
{{block()}} on the same {{Mono}} fails with {{DaprException: UNAVAILABLE: io
exception}}.
h3. Reproduction
Four new tests in {{DaprStateTest}} (mocked {{DaprClient}} as in the existing
tests; the mocked {{Mono}} stores the states or operations of the request when
it is subscribed to, or fails). On main, twice:
{noformat}
testSaveBulkSendsTheStates: expected: <[StateKeyValue{key='k1',
...}, StateKeyValue{key='k2', ...}]> but was: <[]>
testSaveBulkFailure: Expected
java.lang.IllegalStateException to be thrown, but nothing was thrown.
testExecuteTransactionSendsTheOperations: expected:
<[TransactionalStateOperation{operationType='UPSERT', ...}]> but was: <[]>
testExecuteTransactionFailure: Expected
java.lang.IllegalStateException to be thrown, but nothing was thrown.
{noformat}
The existing {{testSaveBulk}} and {{testExecuteTransaction}} return
{{Mono.empty()}} and only check the response object, so they do not notice it.
h3. Proposed fix
{{saveBulkState}} and {{executeStateTransaction}} block on the {{Mono}}, as the
other four state operations do. The request is sent, and a request that Dapr
rejects (or a sidecar that cannot be reached) fails the exchange. 4.23 upgrade
guide note added next to the existing camel-dapr note. camel-dapr with the fix:
64 tests, 0 failures.
Found with a search for calls on asynchronous clients whose result is dropped,
and a small Lean 4 model of the handler (the store as key/value pairs, a Mono
as a deferred function that may fail): main is proved to leave the store
unchanged and to report success for every request, so it is wrong whenever the
request would change the store or would be rejected; the fix is proved equal to
"apply the operations or fail the exchange". Confirmed with the real handler,
and the laziness of the Mono with the real client.
Affected: main, camel-4.22.x, camel-4.18.x, camel-4.14.x (same two lines,
GitHub contents API); the component was added in 4.12.
Duplicate check (2026-10-11): JIRA text "dapr" with "saveBulk",
"executeTransaction" or "state" (1: CAMEL-23630, header filter); GitHub open
pull requests for camel-dapr: none. No open pull request changes
{{DaprStateHandler}}.
_Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v8.20.10#820010)