[ 
https://issues.apache.org/jira/browse/CAMEL-25288?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Claus Ibsen resolved CAMEL-25288.
---------------------------------
    Resolution: Fixed

Fixed via https://github.com/apache/camel/pull/27320

> camel-dapr - the consumers close the configured or autowired Dapr clients 
> when they stop, and the configuration consumer fails to start in a route with 
> a NullPointerException
> ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: CAMEL-25288
>                 URL: https://issues.apache.org/jira/browse/CAMEL-25288
>             Project: Camel
>          Issue Type: Bug
>          Components: camel-dapr
>            Reporter: shashank
>            Assignee: shashank
>            Priority: Major
>             Fix For: 4.23.0
>
>
> The {{client}}, {{previewClient}} and {{workflowClient}} options are 
> autowired ({{@Metadata(autowired = true)}}): a single {{DaprClient}} / 
> {{DaprPreviewClient}} bean in the registry (for example the beans of the Dapr 
> Spring Boot starter) is used by every dapr endpoint. The consumers close 
> clients that they do not own:
> h3. 1. DaprPubSubConsumer closes a configured or autowired preview client
> {code:java}
> protected void doStop() throws Exception {
>     if (subscription != null) {
>         subscription.close();
>     }
>     if (client != null) {
>         client.close();   // also the configured / autowired previewClient
>     }
>     ...
> {code}
> After the route is stopped (or restarted), every other dapr endpoint using 
> that client fails (the gRPC channel is shut down), and the route itself 
> cannot subscribe again: a route restart creates a new consumer, which gets 
> the same closed client from the configuration.
> h3. 2. DaprConfigurationConsumer closes the client of its endpoint, and never 
> ends its subscription
> {code:java}
> protected void doStop() throws Exception {
>     if (client != null) {
>         client.unsubscribeConfiguration(subscriptionId, configStore);   // a 
> Mono that is never subscribed: does nothing
>         client.close();                                                 // 
> the endpoint's client
>     }
>     ...
> {code}
> The client is {{endpoint.getClient()}}: the configured / autowired 
> {{DaprClient}} shared by all dapr endpoints, or the client that the endpoint 
> created for all its producers and consumers. The {{Flux}} subscription is 
> never disposed and the unsubscribe {{Mono}} is never subscribed, so the 
> subscription is not ended at Dapr when the client is not closed. The 
> subscription id was only recorded from a response without items.
> h3. 3. DaprConfigurationConsumer cannot start in a route
> The consumer takes {{endpoint.getClient()}} in its constructor, but the 
> endpoint creates (or takes the configured) client in {{doStart}}, and a route 
> creates its consumer before it starts the endpoint. In a route the consumer 
> has no client and the route fails to start:
> {noformat}
> FailedToStartRoute Failed to start route: configuration because: Cannot invoke
> "io.dapr.client.DaprClient.subscribeConfiguration(io.dapr.client.domain.SubscribeConfigurationRequest)"
>  because "this.client" is null
> {noformat}
> The existing unit test builds the consumer with a mocked endpoint whose 
> client is already set, so it did not show this.
> h3. Reproduction (unit tests, no Dapr sidecar)
> {{DaprConsumerSharedClientTest}}: a {{CamelTestSupport}} test with mocked 
> {{DaprClient}}, {{DaprPreviewClient}} and {{DaprWorkflowClient}} beans in the 
> registry (autowired), a {{dapr:pubSub}} route and a {{dapr:configuration}} 
> route.
> * Stop and start the pub/sub route: on main {{previewClient.close()}} is 
> called ({{NeverWantedButInvoked: daprPreviewClient.close()}}).
> * Start the configuration route: on main it fails with the 
> {{NullPointerException}} above. With only the client taken in {{doStart}}, 
> stopping it does not end the subscription ({{expected: <true> but was: 
> <false>}}), does not unsubscribe and closes the shared client.
> * The existing {{DaprPubSubConsumerTest}} / {{DaprConfigurationConsumerTest}} 
> asserted {{close()}} on the configured / endpoint client; they now assert 
> that it is not closed (and that the configuration consumer unsubscribes with 
> the subscription id).
> h3. Proposed fix
> Ownership as in the other components (for example the AWS components close 
> only the clients that they created):
> * {{DaprPubSubConsumer}} closes only a preview client that it created (none 
> configured); then a restart creates a new one.
> * {{DaprConfigurationConsumer}} takes the endpoint's client in {{doStart}}, 
> records the subscription id from every response, and on stop disposes its 
> subscription and unsubscribes (blocking up to 10 seconds, a failure is 
> logged), without closing the client. Both are needed with Dapr Java SDK 
> 1.18.1: its {{Flux}} does not cancel the gRPC stream when it is disposed, so 
> the explicit {{unsubscribeConfiguration}} is what ends the subscription at 
> the sidecar (the sidecar logs that this call is deprecated in favour of 
> disconnecting).
> * {{DaprEndpoint}} closes the {{DaprClient}}, {{DaprPreviewClient}} and 
> {{DaprWorkflowClient}} that it created in {{doStart}} when it stops (as 
> {{Sqs2Endpoint}} does), never the configured or autowired ones; it creates 
> new ones when it is started again.
> No upgrade note: a configured or autowired client was closed by Camel and now 
> stays open for its owner (Spring or the application), as for the other 
> components.
> {{DaprEndpointClientOwnershipTest}} (2): the endpoint closes the clients it 
> created (Mockito {{mockConstruction}} of {{DaprClientBuilder}} / 
> {{DaprWorkflowClient}}; fails without the endpoint change: {{Wanted but not 
> invoked: daprClient.close()}}) and never the configured ones, which it uses 
> again after a restart.
> With the fix the camel-dapr unit tests pass (56).
> Affected: 4.14.x, 4.18.x and main (same code).
> Duplicate check (2026-10-03): JIRA component camel-dapr / text "dapr" (9 
> issues): CAMEL-25274 (ours, acknowledgement), CAMEL-23645 (open, move to the 
> new Topic API), feature issues. GitHub pull requests 
> "DaprConfigurationConsumer", "camel-dapr close client": none.
> _Filed with Claude Code on behalf of allthingssecurity._



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

Reply via email to