Skip to content

CAMEL-24919: report Debezium consumer startup readiness - #27507

Merged
davsclaus merged 2 commits into
apache:mainfrom
oscerd:fix/CAMEL-24919-debezium-readiness
Oct 10, 2026
Merged

davsclaus merged 2 commits into
apache:mainfrom
oscerd:fix/CAMEL-24919-debezium-readiness

Conversation

@oscerd

@oscerd oscerd commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Debezium consumer health checks currently report UP while their connector tasks are still starting. Honor the configured health-check initial state (DOWN by default) until the engine invokes its pollingStarted callback, then report UP even when no change events have arrived. Reset readiness on each consumer start and preserve engine-failure reporting.

CAMEL-24889 deliberately scoped its original health check to engine failures; this adds the startup signal deferred to CAMEL-24919. Debezium's polling callback signals that tasks have started and polling is enabled, before actual polling. It does not guarantee that an initial snapshot has completed. The component documentation and 4.23 upgrade guide describe this distinction and the camel.health.initial-state=up compatibility setting.

Review feedback addressed (commit 2a9e482)

Following @davsclaus' review:

  • Readiness is now cleared when polling stops. pollingStopped() is overridden, so an engine that completes on its own — without reporting a failure — no longer leaves the check reporting UP while no change event is consumed. Verified against the debezium-api 3.6.3 bytecode that ConnectorCallback.pollingStopped() is part of the contract (a default method, like pollingStarted).
  • The auto-created health check is now covered. theAutoCreatedHealthCheckReportsTheInitialStateUntilPolling exercises the check the consumer builds for itself in doBuild(), rather than one constructed by the test, and pins its type, id, initial state and transition to UP. Note that getHealthCheck() is null until the consumer starts, since doBuild() runs as part of the start lifecycle and the route is autoStartup(false).
  • The three engine state resets are grouped before super.doStart().
  • The test writes to target/data, matching DebeziumConsumerEngineFailureTest.

Rebased onto main. The upgrade-guide entry was previously appended at the end of the file, which placed it under the == Route reload level-2 section; it now sits next to === camel-debezium - a failed embedded engine is now reported, the CAMEL-24889 entry it follows on from.

Validation

  • A real embedded file connector waits on a startup latch, covering DOWN/UP/UNKNOWN initial states, disabled checks, readiness without records, and repeated starts of the same consumer. The original implementation failed the DOWN and UNKNOWN startup assertions.
  • The new pollingStopped assertion was confirmed to be a genuine regression pin: removing the override makes it fail with expected: <false> but was: <true>.
  • camel-debezium-common module tests: 22 passed, zero failures/errors/skips.
  • Formatter and import sorting applied.

CAMEL-24919 · Debezium 3.6.3 callback contract

Original changeset AI-generated by Codex on behalf of @oscerd; review feedback addressed by Claude Code on behalf of @oscerd.

🤖 Generated with Claude Code

@oscerd oscerd added the enhancement New feature or request label Oct 7, 2026
@oscerd oscerd self-assigned this Oct 7, 2026
@oscerd
oscerd requested review from davsclaus and gzurowski October 7, 2026 13:32

@davsclaus davsclaus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this, it closes the startup gap that CAMEL-24889 deliberately left open, and the real-engine test with the startup latch is a nice way to pin the timing down.

I checked the callback contract against the Debezium 3.6.3 AsyncEmbeddedEngine: pollingStarted is invoked after all tasks have started and before polling begins, so the docs' "does not indicate that an initial snapshot has completed" wording is accurate. Reading the initial state in the constructor matches ScheduledPollConsumerHealthCheck, and since the check is readiness-only by default, a slow connector start cannot trip a liveness probe.

A few optional suggestions, none blocking:

  • Test coverage of the real wiring: DebeziumConsumerReadinessTest replaces the registry with a Mockito mock and constructs the health check by hand, so the check the consumer creates itself in doBuild() (and the order in which it reads the initial state) is not exercised. One assertion on the auto-created check would cover that.
  • Nit: engineReady is reset before super.doStart() while engineFailure / engineStopped are reset after it; grouping the three resets would read a little more clearly.
  • Nit: the new test writes its files to the system temp dir, whereas the sibling DebeziumConsumerEngineFailureTest uses target/data.

This review covers project conventions only and does not replace CodeRabbit, Sourcery or SonarCloud.

This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

oscerd and others added 2 commits October 9, 2026 10:49
Co-authored-by: Codex <noreply@openai.com>
Signed-off-by: Andrea Cosentino <ancosen@gmail.com>
- clear engineReady in pollingStopped(), so a self-completing engine no
  longer reports UP while no change event is consumed
- cover the health check the consumer auto-creates in doBuild(), instead
  of only a hand-constructed one
- group the three engine state resets before super.doStart()
- write the test files to target/data, as DebeziumConsumerEngineFailureTest does

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@oscerd
oscerd force-pushed the fix/CAMEL-24919-debezium-readiness branch from 8b4437b to 2a9e482 Compare October 9, 2026 08:54
@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

🌟 Thank you for your contribution to the Apache Camel project! 🌟
🤖 CI automation will test this PR automatically.

🐫 Apache Camel Committers, please review the following items:

  • First-time contributors require MANUAL approval for the GitHub Actions to run
  • You can use the command /component-test (camel-)component-name1 (camel-)component-name2.. to request a test from the test bot although they are normally detected and executed by CI.
  • You can label PRs using skip-tests and test-dependents to fine-tune the checks executed by this PR.
  • Build and test logs are available in the summary page. Only Apache Camel committers have access to the summary.

⚠️ Be careful when sharing logs. Review their contents before sharing them publicly.

@oscerd

oscerd commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the review — all four points are in, pushed as 2a9e482 on top of a rebase onto main.

1. engineReady never cleared (inline) — overrode pollingStopped(). Replied in the thread with the javap check on the ConnectorCallback contract and proof the new assertion fails without the change.

2. Test coverage of the real wiring — added theAutoCreatedHealthCheckReportsTheInitialStateUntilPolling, which uses the check the consumer builds for itself and never calls setHealthCheck. It asserts the type, the id (consumer:readiness), that it reports the registry initial state while the task is held in startup, and that it flips to UP once polling begins.

Worth noting what this surfaced: getHealthCheck() is null until the consumer is started, because doBuild() runs as part of the consumer's start lifecycle and the route is autoStartup(false). So the assertion has to come after consumer.start() — which is precisely the ordering the old test was papering over by constructing the check by hand.

3. Nit — grouped resets — engineReady, engineFailure and engineStopped are now reset together before super.doStart().

4. Nit — temp dir — the test now writes to target/data, matching DebeziumConsumerEngineFailureTest.

Rebase: the branch was 106 commits behind and the upgrade guide conflicted. While resolving it I noticed my entry had been appended at the end of the file, which puts it under the == Route reload level-2 section rather than in the 4.23 component list — the same placement problem you flagged on #27503. Moved it next to === camel-debezium - a failed embedded engine is now reported, the CAMEL-24889 entry it follows on from.

Verification: camel-debezium-common is green — 22 tests, 0 failures.

Not resolving the conversation, leaving that to you.

Claude Code on behalf of @oscerd

@gnodet-bot gnodet-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. The readiness deferral via pollingStarted()/pollingStopped() is correctly scoped, all state is reset before super.doStart() on restart, and the real-engine integration test with the startup latch cleanly covers DOWN/UNKNOWN initial states that the old code would have reported as UP. No issues found.

This review was generated by an AI agent, Hermès on behalf of @gnodet.

@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

🧪 CI tested the following changed modules:

  • catalog/camel-catalog
  • components/camel-debezium/camel-debezium-common/camel-debezium-common-component
  • components/camel-debezium/camel-debezium-db2
  • components/camel-debezium/camel-debezium-mongodb
  • components/camel-debezium/camel-debezium-mysql
  • components/camel-debezium/camel-debezium-oracle
  • components/camel-debezium/camel-debezium-postgres
  • components/camel-debezium/camel-debezium-sqlserver
  • docs

🔬 Scalpel shadow comparison — Scalpel: 15 of 704 tested, 25 compile-only — current: 15 all tested

Maveniverse Scalpel detected 15 affected modules (current approach: 15).

Skip-tests mode would test 15 modules (9 direct + 8 downstream), skip tests for 25 (generated code, meta-modules)

Modules Scalpel would test (15)
  • camel-debezium-common ← components/camel-debezium/camel-debezium-common/camel-debezium-common-component/src/main/java/org/apache/camel/component/debezium/DebeziumConsumer.java, components/camel-debezium/camel-debezium-common/camel-debezium-common-component/src/main/java/org/apache/camel/component/debezium/DebeziumConsumerHealthCheck.java, components/camel-debezium/camel-debezium-common/camel-debezium-common-component/src/test/java/org/apache/camel/component/debezium/DebeziumConsumerReadinessTest.java
  • camel-debezium-db2 ← components/camel-debezium/camel-debezium-db2/src/main/docs/debezium-db2-component.adoc
  • camel-debezium-mongodb ← components/camel-debezium/camel-debezium-mongodb/src/main/docs/debezium-mongodb-component.adoc
  • camel-debezium-mysql ← components/camel-debezium/camel-debezium-mysql/src/main/docs/debezium-mysql-component.adoc
  • camel-debezium-oracle ← components/camel-debezium/camel-debezium-oracle/src/main/docs/debezium-oracle-component.adoc
  • camel-debezium-postgres ← components/camel-debezium/camel-debezium-postgres/src/main/docs/debezium-postgres-component.adoc
  • camel-debezium-sqlserver ← components/camel-debezium/camel-debezium-sqlserver/src/main/docs/debezium-sqlserver-component.adoc
  • camel-jbang-mcp ← downstream of org.apache.camel:camel-catalog
  • camel-jbang-plugin-mcp ← downstream of org.apache.camel:camel-jbang-core
  • camel-jbang-plugin-route-parser ← downstream of org.apache.camel:camel-route-parser
  • camel-jbang-plugin-tui ← downstream of org.apache.camel:camel-catalog
  • camel-jbang-plugin-validate ← downstream of org.apache.camel:camel-yaml-dsl-validator
  • camel-launcher-container ← downstream of org.apache.camel:camel-launcher
  • camel-yaml-dsl-validator ← downstream of org.apache.camel:camel-catalog
  • camel-yaml-dsl-validator-maven-plugin ← downstream of org.apache.camel:camel-yaml-dsl-validator
Modules with tests skipped (25)
  • apache-camel
  • camel-allcomponents
  • camel-catalog-console
  • camel-catalog-maven
  • camel-catalog-suggest
  • camel-componentdsl
  • camel-endpointdsl
  • camel-endpointdsl-support
  • camel-itest
  • camel-jbang-core
  • camel-jbang-it
  • camel-jbang-main
  • camel-jbang-plugin-edit
  • camel-jbang-plugin-generate
  • camel-jbang-plugin-kubernetes
  • camel-jbang-plugin-test
  • camel-kamelet-main
  • camel-launcher
  • camel-report-maven-plugin
  • camel-route-parser
  • camel-yaml-dsl
  • camel-yaml-dsl-deserializers
  • camel-yaml-dsl-maven-plugin
  • coverage
  • dummy-component

ℹ️ Shadow mode — Scalpel observes but does not affect test execution. Learn more

All tested modules (42 modules, 6m 48s total)

Total reactor time: 6m 48s

Module Duration Status
Camel :: Launcher 52.8s SUCCESS
Camel :: JBang :: Plugin :: TUI 44.1s SUCCESS
Camel :: JBang :: MCP 40.1s SUCCESS
Camel :: Component DSL 33.1s SUCCESS
Camel :: Catalog :: Camel Catalog 23.5s SUCCESS
Camel :: Debezium :: Common 21.6s SUCCESS
Camel :: YAML DSL :: Validator 20.1s SUCCESS
Camel :: YAML DSL 18.5s SUCCESS
Camel :: Docs 15.5s SUCCESS
Camel :: JBang :: Plugin :: Validate 15.2s SUCCESS
Camel :: JBang :: Plugin :: Testing 13.7s SUCCESS
Camel :: JBang :: Plugin :: Kubernetes 11.3s SUCCESS
Camel :: Kamelet Main 10.6s SUCCESS
Camel :: YAML DSL :: Deserializers 8.0s SUCCESS
Camel :: Catalog :: Camel Route Parser 7.8s SUCCESS
Camel :: Debezium :: Oracle 6.9s SUCCESS
Camel :: Catalog :: Camel Report Maven Plugin 6.8s SUCCESS
Camel :: Debezium :: PostgreSQL 6.4s SUCCESS
Camel :: Debezium :: SQL Server 6.4s SUCCESS
Camel :: Debezium :: MySQL 5.0s SUCCESS
Camel :: Debezium :: MongoDB 5.0s SUCCESS
Camel :: All Components Sync point 5.0s SUCCESS
Camel :: YAML DSL :: Validator Maven Plugin 4.5s SUCCESS
Camel :: Debezium :: DB2 3.9s SUCCESS
Camel :: YAML DSL :: Maven Plugins 3.0s SUCCESS
Camel :: Catalog :: Maven 2.8s SUCCESS
Camel :: Catalog :: Suggest (deprecated) 2.2s SUCCESS
Camel :: Assembly 2.0s SUCCESS
Camel :: Coverage 1.7s SUCCESS
Camel :: JBang :: Plugin :: Edit 1.5s SUCCESS
Camel :: JBang :: Plugin :: Generate 1.3s SUCCESS
Camel :: JBang :: Plugin :: MCP 1.2s SUCCESS
Camel :: Endpoint DSL :: Support 1.2s SUCCESS
Camel :: JBang :: Main 1.0s SUCCESS
Camel :: JBang :: Integration tests 1.0s SUCCESS
Camel :: Catalog :: Dummy Component 0.9s SUCCESS
Camel :: Catalog :: Console 0.8s SUCCESS
Camel :: JBang :: Plugin :: Route Parser 0.8s SUCCESS
Camel :: Launcher :: Container 0.7s SUCCESS
Camel :: Endpoint DSL n/a
Camel :: Integration Tests n/a
Camel :: JBang :: Core n/a

Top 20 slowest modules:

  • Camel :: Launcher (52.8s)
  • Camel :: JBang :: Plugin :: TUI (44.1s)
  • Camel :: JBang :: MCP (40.1s)
  • Camel :: Component DSL (33.1s)
  • Camel :: Catalog :: Camel Catalog (23.5s)
  • Camel :: Debezium :: Common (21.6s)
  • Camel :: YAML DSL :: Validator (20.1s)
  • Camel :: YAML DSL (18.5s)
  • Camel :: Docs (15.5s)
  • Camel :: JBang :: Plugin :: Validate (15.2s)
  • Camel :: JBang :: Plugin :: Testing (13.7s)
  • Camel :: JBang :: Plugin :: Kubernetes (11.3s)
  • Camel :: Kamelet Main (10.6s)
  • Camel :: YAML DSL :: Deserializers (8.0s)
  • Camel :: Catalog :: Camel Route Parser (7.8s)
  • Camel :: Debezium :: Oracle (6.9s)
  • Camel :: Catalog :: Camel Report Maven Plugin (6.8s)
  • Camel :: Debezium :: PostgreSQL (6.4s)
  • Camel :: Debezium :: SQL Server (6.4s)
  • Camel :: Debezium :: MySQL (5.0s)

⚙️ View full build and test results

@oscerd
oscerd requested a review from davsclaus October 9, 2026 10:54
@oscerd

oscerd commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

All checks are now green (5 pass, Sonar skipped) and every review point is addressed, so I have re-requested your review, @davsclaus.

The review conversations are intentionally left unresolved for you to close after checking.

Claude Code on behalf of @oscerd

@davsclaus davsclaus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @oscerd, all four points from my earlier review are in.

  • pollingStopped() now clears engineReady. I checked the Debezium 3.6.3 AsyncEmbeddedEngine bytecode: the callback is invoked at the end of runTasksPolling, so it fires both when the engine is closed and when polling ends on its own. The assertFalse(consumer.isEngineReady()) after stop() pins it.
  • theAutoCreatedHealthCheckReportsTheInitialStateUntilPolling exercises the check the consumer builds itself in doBuild(), including reading the initial state when it is built.
  • The three engine state resets are grouped before super.doStart(), and the test writes to target/data like DebeziumConsumerEngineFailureTest.

After the rebase, the upgrade-guide entry sits right after the CAMEL-24889 camel-debezium entry, inside the 4.22 to 4.23 section. The regenerated catalog doc copies match the component docs. CI is green.

One small side effect of the pollingStopped() change: an engine that finishes on its own without a failure now reports the initial state (DOWN by default) instead of UP. That is the right signal, since no more change events are consumed. I mention it only so it doesn't come as a surprise.

This review was generated by an AI agent (Claude Code on behalf of Claus Ibsen) and may contain inaccuracies. Please verify all suggestions before applying.

@davsclaus davsclaus added this to the 4.23.0 milestone Oct 10, 2026
@davsclaus
davsclaus merged commit b8af714 into apache:main Oct 10, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants