[ 
https://issues.apache.org/jira/browse/CAMEL-24889?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18117944#comment-18117944
 ] 

Andrea Cosentino commented on CAMEL-24889:
------------------------------------------

PR opened: https://github.com/apache/camel/pull/26733

The embedded engine never rethrows out of {{run()}} - 
{{AsyncEmbeddedEngine.run()}} catches {{Throwable}} itself and reports through 
the {{CompletionCallback}} - so the consumer now registers that callback, hands 
the failure to the exception handler and reports {{DOWN}} from a new consumer 
health check. Verified by reverting the fix: the new test then fails on the 
exception-handler assertion.

----
_Claude Code on behalf of oscerd (Andrea Cosentino)._

> camel-debezium - the consumer is never told that the embedded engine has 
> failed
> -------------------------------------------------------------------------------
>
>                 Key: CAMEL-24889
>                 URL: https://issues.apache.org/jira/browse/CAMEL-24889
>             Project: Camel
>          Issue Type: Bug
>          Components: camel-debezium
>            Reporter: Andrea Cosentino
>            Assignee: Andrea Cosentino
>            Priority: Major
>
> h3. Summary
> When the embedded Debezium engine dies, nothing in Camel is told. The route 
> stays {{Started}}, the
> health check stays {{UP}}, and no change event is ever delivered again. The 
> consumer's own error
> handling for this case cannot run.
> h3. Details
> {{DebeziumConsumer.doStart()}} submits the engine to a single-thread executor 
> and guards it:
> {code:java}
> executorService.submit(
>         () -> {
>             try {
>                 dbzEngine.run();
>             } catch (Throwable e) {
>                 LOG.error("Debezium engine has failed: {}", e.getMessage(), 
> e);
>             }
>         });
> {code}
> That {{catch}} is unreachable. {{DebeziumEngine.create(Connect.class)}} 
> resolves through
> {{META-INF/services/io.debezium.engine.DebeziumEngine$BuilderFactory}} to
> {{ConvertingAsyncEngineBuilderFactory}}, i.e. an {{AsyncEmbeddedEngine}}. 
> Disassembling
> {{AsyncEmbeddedEngine.run()}} from {{debezium-embedded}} shows the whole body 
> wrapped in its own
> {{catch (Throwable)}} (exception table: {{from 2 to 196 target 204 Class 
> java/lang/Throwable}}),
> which calls {{closeEngineWithException(t)}} - logging {{"Engine has failed 
> with"}} - and then
> {{finishShutDown(t)}} -> {{callCompletionHandler(t)}}. {{run()}} never 
> rethrows.
> The only failure signal the engine offers is the {{CompletionCallback}} 
> passed to the builder, and
> {{createDbzEngine()}} does not register one (nor a {{ConnectorCallback}}). So:
> * the failure is invisible to Camel's error handling - 
> {{getExceptionHandler()}} is only ever called
>   from {{onEventListener}}, i.e. for a failure of the *route*, never for a 
> failure of the *engine*;
> * it is invisible to health checks - {{ConsumerHealthCheck.doCallCheck}} only 
> consults a consumer
>   {{if (up && !external && consumer instanceof HealthCheckAware)}}, and 
> {{DebeziumConsumer}} does not
>   implement {{HealthCheckAware}}. The route reports UP while consuming 
> nothing.
> Any connector-level failure therefore produces a silently dead route: wrong 
> credentials, an
> unreachable database, a missing table, a failed snapshot, or an offset store 
> that cannot be opened.
> h3. Second symptom, same root cause
> Once the engine has failed its state is {{STOPPED}}, and 
> {{AsyncEmbeddedEngine.close()}} throws on
> that state ({{"Engine has been already shut down."}}). 
> {{DebeziumConsumer.doStop()}} calls it
> unguarded:
> {code:java}
> protected void doStop() throws Exception {
>     if (dbzEngine != null) {
>         dbzEngine.close();
>     }
>     
> getEndpoint().getCamelContext().getExecutorServiceManager().shutdownGraceful(executorService);
>     super.doStop();
> }
> {code}
> Stopping the route after the engine has died therefore throws, the 
> single-thread executor is never
> shut down, and {{super.doStop()}} never runs.
> h3. Proposed fix
> * Register a {{DebeziumEngine.CompletionCallback}} and route a failure to
>   {{getExceptionHandler().handleException(...)}}, so the component honours 
> the normal Camel consumer
>   failure contract.
> * Make {{DebeziumConsumer}} {{HealthCheckAware}} so that an engine that has 
> stopped with an error
>   takes the route's health check DOWN.
> * Guard {{dbzEngine.close()}} so a stop after engine death does not skip the 
> rest of {{doStop()}}.
> The existing {{FileConnectorEmbeddedDebeziumConfiguration}} test harness in
> {{camel-debezium-common-component}} can drive a connector that fails to 
> start, so this is testable
> without a database.
> ----
> _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