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)