shashank created CAMEL-26044:
--------------------------------

             Summary: camel-dapr - the pub/sub consumer never receives again 
after its stream to the Dapr sidecar fails
                 Key: CAMEL-26044
                 URL: https://issues.apache.org/jira/browse/CAMEL-26044
             Project: Camel
          Issue Type: Bug
          Components: camel-dapr
            Reporter: shashank
            Assignee: shashank


The {{dapr:pubSub}} consumer subscribes once, in {{doStart}}, with 
{{DaprPreviewClient.subscribeToEvents(pubSubName, topic, listener, type)}} 
(main 9f839f4bcc9d). In dapr-sdk 1.18.1 the returned {{Subscription}} runs a 
receiver thread that opens the gRPC stream and then waits on a semaphore. Only 
the stream observer's {{onCompleted}} releases it, and then a new stream is 
opened. The observer's {{onError}} only calls 
{{listener.onError(DaprException.propagate(t))}} and returns. So after a failed 
stream (the sidecar restarts, {{UNAVAILABLE}}, a reset connection) no new 
stream is ever opened. {{DaprPubSubConsumer.DaprSubscriptionListener.onError}} 
only logs at ERROR. The route stays started and receives no further event until 
it is restarted. The configuration consumer has the same problem (CAMEL-25844).

*Fix*: when the listener gets an error caused by a gRPC 
{{StatusRuntimeException}} (the stream failed), the consumer closes the 
subscription and subscribes again after a delay: 1 second first, then doubling 
up to 30 seconds while subscriptions keep failing. The delay starts again at 1 
second once an event is received. The Dapr client also calls {{onError}} for an 
event it could not convert and when {{onEvent}} fails, and the stream stays 
open then: those errors are only logged, as before. A failed 
{{subscribeToEvents}} goes to the consumer's exception handler and is tried 
again. One lock guards the subscription and the pending resubscribe; {{doStop}} 
cancels a pending resubscribe, and a resubscribe checks {{isRunAllowed()}}. One 
WARN per failure; the new subscription request is logged at DEBUG (the Dapr 
client opens the stream afterwards), and one INFO on the first event of the new 
stream. The component page says that the consumer subscribes again.

*Tests*: new {{DaprPubSubConsumerResubscribeTest}}, 6 tests: a route with a 
Mockito {{DaprPreviewClient}} in the registry, and a failed stream simulated as 
the Dapr client does it 
({{listener.onError(DaprException.propagate(Status.UNAVAILABLE.asRuntimeException()))}}).
* {{subscribesAgainWhenTheStreamFails}} fails on main: {{the consumer must 
subscribe again after the stream failed ==> expected: <true> but was: <false>}};
* {{aFailureToSubscribeAgainGoesToTheExceptionHandlerAndIsTriedAgain}}, 
{{theDelayDoublesWhileTheStreamFailsAndStartsAgainOnAnEvent}} and 
{{aLateErrorOfAReplacedSubscriptionIsIgnored}} cover the other paths of the 
resubscribe (a failing {{subscribeToEvents}}, the delay 1 s, 2 s, 4 s and its 
reset by an event, a late error of a replaced subscription);
* {{anErrorThatDoesNotEndTheStreamKeepsTheSubscription}} and 
{{stoppingTheRouteCancelsAPendingResubscribe}} are controls that pass on main 
and with the fix.
Unit tests of camel-dapr with the fix: 70 run, 0 failures.

*Not changed*: {{DaprEndpoint.createConsumer}} does not call 
{{configureConsumer}}, so the {{exceptionHandler}} and {{bridgeErrorHandler}} 
endpoint options do not reach the dapr consumers (follow-up if wanted).

*How it was found*: propagation of our fix pattern "terminal callback of a 
watch/stream only logs, no resubscribe" (CAMEL-25730, CAMEL-25680, 
CAMEL-25844), with the library behaviour read from the dapr-sdk 1.18.1 jar 
({{Subscription}}, {{Subscription$1}}).

*Affected*: main, camel-4.23.x, camel-4.22.x and camel-4.18.x (same consumer). 
Read, not run.

_Filed with Claude Code on behalf of allthingssecurity._



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to