This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new b8af714acd6b CAMEL-24919: report Debezium consumer startup readiness
b8af714acd6b is described below
commit b8af714acd6b159848af95224f920e2bf37f7744
Author: Andrea Cosentino <[email protected]>
AuthorDate: Sat Oct 10 08:41:25 2026 +0200
CAMEL-24919: report Debezium consumer startup readiness
Debezium consumer health checks reported UP while their connector tasks
were still starting. The check now keeps the configured health-check
initial state (DOWN by default) until the engine invokes its
pollingStarted callback, then reports UP even when no change events have
arrived. Readiness is reset on each consumer start and cleared when
polling stops, so an engine that completes on its own no longer keeps
reporting UP. Engine-failure reporting from CAMEL-24889 is unchanged.
pollingStarted signals that tasks have started and polling is enabled; it
does not mean an initial snapshot has completed. The component docs and
the 4.23 upgrade guide describe this and the camel.health.initial-state=up
compatibility setting.
Closes #27507
Co-authored-by: Codex <[email protected]>
Co-Authored-By: Claude Opus 5 <[email protected]>
Signed-off-by: Andrea Cosentino <[email protected]>
---
.../camel/catalog/docs/debezium-db2-component.adoc | 4 +
.../catalog/docs/debezium-mongodb-component.adoc | 4 +
.../catalog/docs/debezium-mysql-component.adoc | 4 +
.../catalog/docs/debezium-oracle-component.adoc | 4 +
.../catalog/docs/debezium-postgres-component.adoc | 4 +
.../catalog/docs/debezium-sqlserver-component.adoc | 4 +
.../camel/component/debezium/DebeziumConsumer.java | 23 ++-
.../debezium/DebeziumConsumerHealthCheck.java | 8 +-
.../debezium/DebeziumConsumerReadinessTest.java | 184 +++++++++++++++++++++
.../src/main/docs/debezium-db2-component.adoc | 4 +
.../src/main/docs/debezium-mongodb-component.adoc | 4 +
.../src/main/docs/debezium-mysql-component.adoc | 4 +
.../src/main/docs/debezium-oracle-component.adoc | 4 +
.../src/main/docs/debezium-postgres-component.adoc | 4 +
.../main/docs/debezium-sqlserver-component.adoc | 4 +
.../ROOT/pages/camel-4x-upgrade-guide-4_23.adoc | 8 +
16 files changed, 267 insertions(+), 4 deletions(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/debezium-db2-component.adoc
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/debezium-db2-component.adoc
index bce0e3bf6f42..d2a57da69f31 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/debezium-db2-component.adoc
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/debezium-db2-component.adoc
@@ -29,6 +29,10 @@ the application will resume from the last recorded offset,
which may result in receiving duplicate events immediately after the restart.
Therefore, your downstream routes should be tolerant enough of such a case and
deduplicate events if needed.
+Before the engine starts polling, the consumer health check reports the
configured initial state
+(`DOWN` by default). It reports `UP` once the connector tasks have started and
the engine enters its polling phase,
+even if no change events have arrived. This does not indicate that an initial
snapshot has completed.
+
If the embedded engine stops with an error, for example because the connector
cannot reach the database or
the offset store cannot be read, it is not restarted: the route stays started
but receives no further events.
The failure is reported to the consumer exception handler and turns the route
health check `DOWN`, so it can
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/debezium-mongodb-component.adoc
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/debezium-mongodb-component.adoc
index 66908454ed35..85c243958bd3 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/debezium-mongodb-component.adoc
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/debezium-mongodb-component.adoc
@@ -35,6 +35,10 @@ the application will resume from the last recorded offset,
which may result in receiving duplicate events immediately after the restart.
Therefore, your downstream routes should be tolerant enough of such a case and
deduplicate events if needed.
+Before the engine starts polling, the consumer health check reports the
configured initial state
+(`DOWN` by default). It reports `UP` once the connector tasks have started and
the engine enters its polling phase,
+even if no change events have arrived. This does not indicate that an initial
snapshot has completed.
+
If the embedded engine stops with an error, for example because the connector
cannot reach the database or
the offset store cannot be read, it is not restarted: the route stays started
but receives no further events.
The failure is reported to the consumer exception handler and turns the route
health check `DOWN`, so it can
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/debezium-mysql-component.adoc
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/debezium-mysql-component.adoc
index e18e387d562e..34b0b811980c 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/debezium-mysql-component.adoc
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/debezium-mysql-component.adoc
@@ -28,6 +28,10 @@ the application will resume from the last recorded offset,
which may result in receiving duplicate events immediately after the restart.
Therefore, your downstream routes should be tolerant enough of such a case and
deduplicate events if needed.
+Before the engine starts polling, the consumer health check reports the
configured initial state
+(`DOWN` by default). It reports `UP` once the connector tasks have started and
the engine enters its polling phase,
+even if no change events have arrived. This does not indicate that an initial
snapshot has completed.
+
If the embedded engine stops with an error, for example because the connector
cannot reach the database or
the offset store cannot be read, it is not restarted: the route stays started
but receives no further events.
The failure is reported to the consumer exception handler and turns the route
health check `DOWN`, so it can
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/debezium-oracle-component.adoc
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/debezium-oracle-component.adoc
index e4a05e2b934d..ea3bb07fbefe 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/debezium-oracle-component.adoc
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/debezium-oracle-component.adoc
@@ -29,6 +29,10 @@ the application will resume from the last recorded offset,
which may result in receiving duplicate events immediately after the restart.
Therefore, your downstream routes should be tolerant enough of such a case and
deduplicate events if needed.
+Before the engine starts polling, the consumer health check reports the
configured initial state
+(`DOWN` by default). It reports `UP` once the connector tasks have started and
the engine enters its polling phase,
+even if no change events have arrived. This does not indicate that an initial
snapshot has completed.
+
If the embedded engine stops with an error, for example because the connector
cannot reach the database or
the offset store cannot be read, it is not restarted: the route stays started
but receives no further events.
The failure is reported to the consumer exception handler and turns the route
health check `DOWN`, so it can
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/debezium-postgres-component.adoc
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/debezium-postgres-component.adoc
index 8b8dca6ad232..7efd8adcf172 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/debezium-postgres-component.adoc
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/debezium-postgres-component.adoc
@@ -29,6 +29,10 @@ the application will resume from the last recorded offset,
which may result in receiving duplicate events immediately after the restart.
Therefore, your downstream routes should be tolerant enough of such a case and
deduplicate events if needed.
+Before the engine starts polling, the consumer health check reports the
configured initial state
+(`DOWN` by default). It reports `UP` once the connector tasks have started and
the engine enters its polling phase,
+even if no change events have arrived. This does not indicate that an initial
snapshot has completed.
+
If the embedded engine stops with an error, for example because the connector
cannot reach the database or
the offset store cannot be read, it is not restarted: the route stays started
but receives no further events.
The failure is reported to the consumer exception handler and turns the route
health check `DOWN`, so it can
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/debezium-sqlserver-component.adoc
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/debezium-sqlserver-component.adoc
index e7a48a170b6b..96bc0187996e 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/debezium-sqlserver-component.adoc
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/debezium-sqlserver-component.adoc
@@ -28,6 +28,10 @@ the application will resume from the last recorded offset,
which may result in receiving duplicate events immediately after the restart.
Therefore, your downstream routes should be tolerant enough of such a case and
deduplicate events if needed.
+Before the engine starts polling, the consumer health check reports the
configured initial state
+(`DOWN` by default). It reports `UP` once the connector tasks have started and
the engine enters its polling phase,
+even if no change events have arrived. This does not indicate that an initial
snapshot has completed.
+
If the embedded engine stops with an error, for example because the connector
cannot reach the database or
the offset store cannot be read, it is not restarted: the route stays started
but receives no further events.
The failure is reported to the consumer exception handler and turns the route
health check `DOWN`, so it can
diff --git
a/components/camel-debezium/camel-debezium-common/camel-debezium-common-component/src/main/java/org/apache/camel/component/debezium/DebeziumConsumer.java
b/components/camel-debezium/camel-debezium-common/camel-debezium-common-component/src/main/java/org/apache/camel/component/debezium/DebeziumConsumer.java
index ebcf9ed3b996..eccc69dfd7b1 100644
---
a/components/camel-debezium/camel-debezium-common/camel-debezium-common-component/src/main/java/org/apache/camel/component/debezium/DebeziumConsumer.java
+++
b/components/camel-debezium/camel-debezium-common/camel-debezium-common-component/src/main/java/org/apache/camel/component/debezium/DebeziumConsumer.java
@@ -42,6 +42,7 @@ public class DebeziumConsumer extends DefaultConsumer {
private DebeziumEngine<ChangeEvent<SourceRecord, SourceRecord>> dbzEngine;
private volatile Throwable engineFailure;
private volatile boolean engineStopped;
+ private volatile boolean engineReady;
public DebeziumConsumer(DebeziumEndpoint endpoint, Processor processor) {
super(endpoint, processor);
@@ -59,11 +60,12 @@ public class DebeziumConsumer extends DefaultConsumer {
@Override
protected void doStart() throws Exception {
- super.doStart();
-
+ engineReady = false;
engineFailure = null;
engineStopped = false;
+ super.doStart();
+
// start a single threaded pool to monitor events
executorService = endpoint.createExecutor(this);
@@ -115,10 +117,27 @@ public class DebeziumConsumer extends DefaultConsumer {
return engineFailure;
}
+ boolean isEngineReady() {
+ return engineReady;
+ }
+
private DebeziumEngine<ChangeEvent<SourceRecord, SourceRecord>>
createDbzEngine() {
return DebeziumEngine.create(Connect.class)
.using(configuration.createDebeziumConfiguration().asProperties())
.using(this::onEngineCompleted)
+ .using(new DebeziumEngine.ConnectorCallback() {
+ @Override
+ public void pollingStarted() {
+ engineReady = true;
+ }
+
+ @Override
+ public void pollingStopped() {
+ // the engine is no longer polling, so it consumes no
further change event, even when it
+ // completed on its own without reporting a failure
+ engineReady = false;
+ }
+ })
.notifying(this::onEventListener)
.build();
}
diff --git
a/components/camel-debezium/camel-debezium-common/camel-debezium-common-component/src/main/java/org/apache/camel/component/debezium/DebeziumConsumerHealthCheck.java
b/components/camel-debezium/camel-debezium-common/camel-debezium-common-component/src/main/java/org/apache/camel/component/debezium/DebeziumConsumerHealthCheck.java
index 4d4ff2e08038..904ef847a7a3 100644
---
a/components/camel-debezium/camel-debezium-common/camel-debezium-common-component/src/main/java/org/apache/camel/component/debezium/DebeziumConsumerHealthCheck.java
+++
b/components/camel-debezium/camel-debezium-common/camel-debezium-common-component/src/main/java/org/apache/camel/component/debezium/DebeziumConsumerHealthCheck.java
@@ -19,6 +19,7 @@ package org.apache.camel.component.debezium;
import java.util.Map;
import org.apache.camel.health.HealthCheck;
+import org.apache.camel.health.HealthCheckRegistry;
import org.apache.camel.health.HealthCheckResultBuilder;
import org.apache.camel.util.URISupport;
@@ -33,9 +34,12 @@ public class DebeziumConsumerHealthCheck implements
HealthCheck {
private final DebeziumConsumer consumer;
private final String id;
private final String sanitizedUri;
+ private final State initialState;
private boolean enabled = true;
public DebeziumConsumerHealthCheck(DebeziumConsumer consumer, String id) {
+ HealthCheckRegistry registry =
HealthCheckRegistry.get(consumer.getEndpoint().getCamelContext());
+ this.initialState = registry != null ? registry.getInitialState() :
State.DOWN;
this.consumer = consumer;
this.id = id;
this.sanitizedUri =
URISupport.sanitizeUri(consumer.getEndpoint().getEndpointUri());
@@ -76,8 +80,8 @@ public class DebeziumConsumerHealthCheck implements
HealthCheck {
final Throwable failure = consumer.getEngineFailure();
if (failure == null) {
- // the engine is either starting, running, or was stopped on
request, none of which is a failure
- return builder.up().build();
+ // Keep the configured initial state until the engine has started
its polling tasks.
+ return builder.state(consumer.isEngineReady() ? State.UP :
initialState).build();
}
builder.down();
diff --git
a/components/camel-debezium/camel-debezium-common/camel-debezium-common-component/src/test/java/org/apache/camel/component/debezium/DebeziumConsumerReadinessTest.java
b/components/camel-debezium/camel-debezium-common/camel-debezium-common-component/src/test/java/org/apache/camel/component/debezium/DebeziumConsumerReadinessTest.java
new file mode 100644
index 000000000000..2b21da39101d
--- /dev/null
+++
b/components/camel-debezium/camel-debezium-common/camel-debezium-common-component/src/test/java/org/apache/camel/component/debezium/DebeziumConsumerReadinessTest.java
@@ -0,0 +1,184 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.debezium;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import
org.apache.camel.component.debezium.configuration.FileConnectorEmbeddedDebeziumConfiguration;
+import org.apache.camel.health.HealthCheck;
+import org.apache.camel.health.HealthCheckRegistry;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.apache.kafka.connect.connector.Task;
+import org.apache.kafka.connect.file.FileStreamSourceConnector;
+import org.apache.kafka.connect.file.FileStreamSourceTask;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
+
+import static org.awaitility.Awaitility.await;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+class DebeziumConsumerReadinessTest extends CamelTestSupport {
+ private static volatile CountDownLatch starting;
+ private static volatile CountDownLatch release;
+ private Path input;
+ private Path offsets;
+ private HealthCheckRegistry registry;
+
+ @ParameterizedTest
+ @EnumSource(HealthCheck.State.class)
+ void readinessWaitsForPollingAndResetsOnRestart(HealthCheck.State
initialState) throws Exception {
+ when(registry.getInitialState()).thenReturn(initialState);
+ DebeziumConsumer consumer = (DebeziumConsumer)
context.getRoute("readiness").getConsumer();
+ // Construct after setting the initial state, as with a consumer built
during context startup.
+ consumer.setHealthCheck(new DebeziumConsumerHealthCheck(consumer,
"consumer:readiness"));
+ HealthCheck check = consumer.getHealthCheck();
+ for (int i = 0; i < 2; i++) {
+ starting = new CountDownLatch(1);
+ release = new CountDownLatch(1);
+ consumer.start();
+ try {
+ assertTrue(starting.await(30, TimeUnit.SECONDS), "the source
task should enter startup");
+ assertEquals(initialState, check.call().getState());
+ check.setEnabled(false);
+ assertEquals(HealthCheck.State.UNKNOWN,
check.call().getState());
+ check.setEnabled(true);
+ release.countDown();
+ await().atMost(30,
TimeUnit.SECONDS).until(consumer::isEngineReady);
+ await().atMost(30, TimeUnit.SECONDS)
+ .untilAsserted(() ->
assertEquals(HealthCheck.State.UP, check.call().getState()));
+ assertEquals(0,
getMockEndpoint("mock:result").getReceivedCounter(),
+ "readiness must not require a change event");
+ } finally {
+ release.countDown();
+ consumer.stop();
+ }
+ }
+ }
+
+ @Test
+ void theAutoCreatedHealthCheckReportsTheInitialStateUntilPolling() throws
Exception {
+ DebeziumConsumer consumer = (DebeziumConsumer)
context.getRoute("readiness").getConsumer();
+ starting = new CountDownLatch(1);
+ release = new CountDownLatch(1);
+ // no setHealthCheck() here: starting the consumer runs doBuild(),
which creates the check itself
+ consumer.start();
+ try {
+ assertTrue(starting.await(30, TimeUnit.SECONDS), "the source task
should enter startup");
+ HealthCheck check = consumer.getHealthCheck();
+ assertInstanceOf(DebeziumConsumerHealthCheck.class, check,
+ "the consumer should create its own health check in
doBuild()");
+ assertEquals("consumer:readiness", check.getId());
+ // DOWN is the registry initial state stubbed in
createCamelContext, read when doBuild() ran
+ assertEquals(HealthCheck.State.DOWN, check.call().getState());
+ release.countDown();
+ await().atMost(30, TimeUnit.SECONDS)
+ .untilAsserted(() -> assertEquals(HealthCheck.State.UP,
check.call().getState()));
+ } finally {
+ release.countDown();
+ consumer.stop();
+ }
+ // the engine left its polling phase, so the consumer no longer
reports itself as ready
+ assertFalse(consumer.isEngineReady(), "stopping the engine should
clear readiness");
+ }
+
+ @AfterEach
+ void cleanup() throws Exception {
+ if (release != null) {
+ release.countDown();
+ }
+ context.stop();
+ Files.deleteIfExists(input);
+ Files.deleteIfExists(offsets);
+ }
+
+ @Override
+ protected CamelContext createCamelContext() throws Exception {
+ CamelContext context = super.createCamelContext();
+ registry = mock(HealthCheckRegistry.class);
+ when(registry.getInitialState()).thenReturn(HealthCheck.State.DOWN);
+
context.getCamelContextExtension().addContextPlugin(HealthCheckRegistry.class,
registry);
+ input = Paths.get("target/data",
"camel-debezium-readiness-input.txt").toAbsolutePath();
+ offsets = Paths.get("target/data",
"camel-debezium-readiness-offset-store.dat").toAbsolutePath();
+ Files.createDirectories(input.getParent());
+ Files.deleteIfExists(input);
+ Files.deleteIfExists(offsets);
+ Files.createFile(input);
+ FileConnectorEmbeddedDebeziumConfiguration configuration = new
FileConnectorEmbeddedDebeziumConfiguration() {
+ @Override
+ protected Class<?> configureConnectorClass() {
+ return DelayedConnector.class;
+ }
+ };
+ configuration.setName("readiness");
+ configuration.setTopicConfig("readiness");
+ configuration.setTestFilePath(input);
+ configuration.setOffsetStorageFileName(offsets.toString());
+ DebeziumTestComponent component = new DebeziumTestComponent(context);
+ component.setConfiguration(configuration);
+ context.addComponent("debezium", component);
+ context.disableJMX();
+ return context;
+ }
+
+ @Override
+ protected RoutesBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+
from("debezium:dummy").routeId("readiness").autoStartup(false).to("mock:result");
+ }
+ };
+ }
+
+ public static class DelayedConnector extends FileStreamSourceConnector {
+ @Override
+ public Class<? extends Task> taskClass() {
+ return DelayedTask.class;
+ }
+ }
+
+ public static class DelayedTask extends FileStreamSourceTask {
+ @Override
+ public void start(Map<String, String> props) {
+ starting.countDown();
+ try {
+ if (!release.await(30, TimeUnit.SECONDS)) {
+ throw new IllegalStateException("Timed out waiting to
release source task startup");
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new IllegalStateException(e);
+ }
+ super.start(props);
+ }
+ }
+}
diff --git
a/components/camel-debezium/camel-debezium-db2/src/main/docs/debezium-db2-component.adoc
b/components/camel-debezium/camel-debezium-db2/src/main/docs/debezium-db2-component.adoc
index bce0e3bf6f42..d2a57da69f31 100644
---
a/components/camel-debezium/camel-debezium-db2/src/main/docs/debezium-db2-component.adoc
+++
b/components/camel-debezium/camel-debezium-db2/src/main/docs/debezium-db2-component.adoc
@@ -29,6 +29,10 @@ the application will resume from the last recorded offset,
which may result in receiving duplicate events immediately after the restart.
Therefore, your downstream routes should be tolerant enough of such a case and
deduplicate events if needed.
+Before the engine starts polling, the consumer health check reports the
configured initial state
+(`DOWN` by default). It reports `UP` once the connector tasks have started and
the engine enters its polling phase,
+even if no change events have arrived. This does not indicate that an initial
snapshot has completed.
+
If the embedded engine stops with an error, for example because the connector
cannot reach the database or
the offset store cannot be read, it is not restarted: the route stays started
but receives no further events.
The failure is reported to the consumer exception handler and turns the route
health check `DOWN`, so it can
diff --git
a/components/camel-debezium/camel-debezium-mongodb/src/main/docs/debezium-mongodb-component.adoc
b/components/camel-debezium/camel-debezium-mongodb/src/main/docs/debezium-mongodb-component.adoc
index 66908454ed35..85c243958bd3 100644
---
a/components/camel-debezium/camel-debezium-mongodb/src/main/docs/debezium-mongodb-component.adoc
+++
b/components/camel-debezium/camel-debezium-mongodb/src/main/docs/debezium-mongodb-component.adoc
@@ -35,6 +35,10 @@ the application will resume from the last recorded offset,
which may result in receiving duplicate events immediately after the restart.
Therefore, your downstream routes should be tolerant enough of such a case and
deduplicate events if needed.
+Before the engine starts polling, the consumer health check reports the
configured initial state
+(`DOWN` by default). It reports `UP` once the connector tasks have started and
the engine enters its polling phase,
+even if no change events have arrived. This does not indicate that an initial
snapshot has completed.
+
If the embedded engine stops with an error, for example because the connector
cannot reach the database or
the offset store cannot be read, it is not restarted: the route stays started
but receives no further events.
The failure is reported to the consumer exception handler and turns the route
health check `DOWN`, so it can
diff --git
a/components/camel-debezium/camel-debezium-mysql/src/main/docs/debezium-mysql-component.adoc
b/components/camel-debezium/camel-debezium-mysql/src/main/docs/debezium-mysql-component.adoc
index e18e387d562e..34b0b811980c 100644
---
a/components/camel-debezium/camel-debezium-mysql/src/main/docs/debezium-mysql-component.adoc
+++
b/components/camel-debezium/camel-debezium-mysql/src/main/docs/debezium-mysql-component.adoc
@@ -28,6 +28,10 @@ the application will resume from the last recorded offset,
which may result in receiving duplicate events immediately after the restart.
Therefore, your downstream routes should be tolerant enough of such a case and
deduplicate events if needed.
+Before the engine starts polling, the consumer health check reports the
configured initial state
+(`DOWN` by default). It reports `UP` once the connector tasks have started and
the engine enters its polling phase,
+even if no change events have arrived. This does not indicate that an initial
snapshot has completed.
+
If the embedded engine stops with an error, for example because the connector
cannot reach the database or
the offset store cannot be read, it is not restarted: the route stays started
but receives no further events.
The failure is reported to the consumer exception handler and turns the route
health check `DOWN`, so it can
diff --git
a/components/camel-debezium/camel-debezium-oracle/src/main/docs/debezium-oracle-component.adoc
b/components/camel-debezium/camel-debezium-oracle/src/main/docs/debezium-oracle-component.adoc
index e4a05e2b934d..ea3bb07fbefe 100644
---
a/components/camel-debezium/camel-debezium-oracle/src/main/docs/debezium-oracle-component.adoc
+++
b/components/camel-debezium/camel-debezium-oracle/src/main/docs/debezium-oracle-component.adoc
@@ -29,6 +29,10 @@ the application will resume from the last recorded offset,
which may result in receiving duplicate events immediately after the restart.
Therefore, your downstream routes should be tolerant enough of such a case and
deduplicate events if needed.
+Before the engine starts polling, the consumer health check reports the
configured initial state
+(`DOWN` by default). It reports `UP` once the connector tasks have started and
the engine enters its polling phase,
+even if no change events have arrived. This does not indicate that an initial
snapshot has completed.
+
If the embedded engine stops with an error, for example because the connector
cannot reach the database or
the offset store cannot be read, it is not restarted: the route stays started
but receives no further events.
The failure is reported to the consumer exception handler and turns the route
health check `DOWN`, so it can
diff --git
a/components/camel-debezium/camel-debezium-postgres/src/main/docs/debezium-postgres-component.adoc
b/components/camel-debezium/camel-debezium-postgres/src/main/docs/debezium-postgres-component.adoc
index 8b8dca6ad232..7efd8adcf172 100644
---
a/components/camel-debezium/camel-debezium-postgres/src/main/docs/debezium-postgres-component.adoc
+++
b/components/camel-debezium/camel-debezium-postgres/src/main/docs/debezium-postgres-component.adoc
@@ -29,6 +29,10 @@ the application will resume from the last recorded offset,
which may result in receiving duplicate events immediately after the restart.
Therefore, your downstream routes should be tolerant enough of such a case and
deduplicate events if needed.
+Before the engine starts polling, the consumer health check reports the
configured initial state
+(`DOWN` by default). It reports `UP` once the connector tasks have started and
the engine enters its polling phase,
+even if no change events have arrived. This does not indicate that an initial
snapshot has completed.
+
If the embedded engine stops with an error, for example because the connector
cannot reach the database or
the offset store cannot be read, it is not restarted: the route stays started
but receives no further events.
The failure is reported to the consumer exception handler and turns the route
health check `DOWN`, so it can
diff --git
a/components/camel-debezium/camel-debezium-sqlserver/src/main/docs/debezium-sqlserver-component.adoc
b/components/camel-debezium/camel-debezium-sqlserver/src/main/docs/debezium-sqlserver-component.adoc
index e7a48a170b6b..96bc0187996e 100644
---
a/components/camel-debezium/camel-debezium-sqlserver/src/main/docs/debezium-sqlserver-component.adoc
+++
b/components/camel-debezium/camel-debezium-sqlserver/src/main/docs/debezium-sqlserver-component.adoc
@@ -28,6 +28,10 @@ the application will resume from the last recorded offset,
which may result in receiving duplicate events immediately after the restart.
Therefore, your downstream routes should be tolerant enough of such a case and
deduplicate events if needed.
+Before the engine starts polling, the consumer health check reports the
configured initial state
+(`DOWN` by default). It reports `UP` once the connector tasks have started and
the engine enters its polling phase,
+even if no change events have arrived. This does not indicate that an initial
snapshot has completed.
+
If the embedded engine stops with an error, for example because the connector
cannot reach the database or
the offset store cannot be read, it is not restarted: the route stays started
but receives no further events.
The failure is reported to the consumer exception handler and turns the route
health check `DOWN`, so it can
diff --git
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
index f77ec1f362c5..ff5a398357c5 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
@@ -4682,6 +4682,14 @@ healthy while no longer receiving any change event.
Deployments that use readine
now see a Debezium route whose engine has died reported as `DOWN`, where it
was previously reported as `UP`.
The engine is still not restarted automatically.
+=== camel-debezium - consumer readiness during startup
+
+Debezium consumer health checks now retain the configured initial state
(`DOWN` by default) until the embedded
+engine has started its connector tasks and enters its polling phase.
Previously, they reported `UP` during startup
+as long as no engine failure had been reported. Readiness does not wait for a
change event or for an initial snapshot
+to complete. To keep the previous optimistic startup behavior, configure
`camel.health.initial-state=up`.
+Engine failures continue to report `DOWN` regardless of the initial state.
+
=== camel-core - event notifier exchange sent and redelivery events
An event notifier now receives the `ExchangeSentEvent` also when it does not
want the `ExchangeSendingEvent`