Andrea Cosentino created CAMEL-24932:
----------------------------------------

             Summary: camel-pulsar - the polling loop dies on a 
NullPointerException when a receive fails
                 Key: CAMEL-24932
                 URL: https://issues.apache.org/jira/browse/CAMEL-24932
             Project: Camel
          Issue Type: Bug
          Components: camel-pulsar
            Reporter: Andrea Cosentino
            Assignee: Andrea Cosentino


h3. Summary

With {{messageListener=false}}, the polling loop reports its own errors through
{{endpoint.getExceptionHandler()}}, which is {{null}} unless the route 
configures one. The resulting
{{NullPointerException}} escapes {{run()}}, the consumer thread dies, and that 
consumer silently stops
receiving messages.

h3. Details

{{PulsarConsumer.PulsarConsumerLoop.run()}}:

{code:java}
while (running && isRunAllowed()) {
    try {
        Message<byte[]> msg = consumer.receive();
        listener.received(consumer, msg);
    } catch (PulsarClientException e) {
        if (e.getCause() instanceof InterruptedException) {
            ...
            running = false;
        } else {
            endpoint.getExceptionHandler().handleException(e);
        }
    } catch (Exception e) {
        endpoint.getExceptionHandler().handleException(e);
    }
}
{code}

{{getExceptionHandler()}} here resolves to {{DefaultEndpoint}}'s {{@UriParam}} 
field, which stays
{{null}} unless the route sets {{?exceptionHandler=#bean}}. 
{{bridgeErrorHandler=true}} does not help
either: {{DefaultEndpoint.configureConsumer}} installs both the bridging 
handler and a custom handler on
the *consumer*, never on the endpoint.

So any {{PulsarClientException}} from {{consumer.receive()}} whose cause is not 
an interrupt - a broker
reconnect, a topic unload, a timeout - and any other {{Exception}}, throws an 
NPE from inside the catch
block. The NPE propagates out of {{run()}} into the {{Future}} returned by 
{{executor.submit(...)}},
which is discarded, so nothing is logged at all. The thread is gone and the 
loop is not restarted, so
that consumer stops consuming for the lifetime of the route.

h3. Scope

Only reachable with {{messageListener=false}}; the default is {{true}}, which 
uses
{{PulsarMessageListener}} instead. That one already does the right thing and 
calls
{{pulsarConsumer.getExceptionHandler()}}.

h3. Proposed fix

Use the consumer's exception handler, which {{DefaultConsumer}} always 
initialises, exactly as
{{PulsarMessageListener}} does. Worth also considering whether the loop should 
keep running after an
unknown error, but the immediate defect is the NPE.

----
_Reported by Claude Code on behalf of oscerd (Andrea Cosentino)._



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

Reply via email to