Skip to content

CAMEL-23994: Fix batching auto-commit committing unprocessed record offsets#24688

Merged
davsclaus merged 1 commit into
mainfrom
fix/CAMEL-23994-batching-overcommit
Jul 14, 2026
Merged

CAMEL-23994: Fix batching auto-commit committing unprocessed record offsets#24688
davsclaus merged 1 commit into
mainfrom
fix/CAMEL-23994-batching-overcommit

Conversation

@davsclaus

Copy link
Copy Markdown
Contributor

Claude Code on behalf of davsclaus

Summary

Fixes Bug 3 from CAMEL-23994: batching auto-commit over-commits unprocessed record offsets.

Root cause: In batching mode, CommitSynchronization.onComplete() called the no-arg commitManager.commit() which commits the Kafka consumer's current position. Because Kafka pre-fetches records ahead of what was actually delivered to the processor, the committed offset jumps past records that haven't been processed yet. On restart, those skipped records are silently lost.

Fix: Compute the maximum offset per TopicPartition from the actual batch exchanges (via their KafkaConstants.TOPIC, PARTITION, and OFFSET headers), then explicitly call commitManager.recordOffset() + commitManager.commit(partition) for each partition. This ensures only offsets of actually-processed records are committed — matching the behavior of the streaming facade.

Changes

  • Added computeBatchOffsets(List<Exchange>) method that extracts max offset per TopicPartition from batch exchange headers
  • Modified CommitSynchronization inner class to accept and use explicit batch offsets instead of committing the consumer's current position
  • Updated autoCommitResultProcessing() to compute and pass batch offsets to CommitSynchronization

Test plan

  • All 141 existing unit tests pass (mvn test in camel-kafka module)
  • CI integration tests (Kafka testcontainers)

Co-Authored-By: Claude Opus 4.6 noreply@anthropic.com

…ffsets

In batching mode, CommitSynchronization.onComplete() called the no-arg
commitManager.commit() which commits the consumer's current position.
Because Kafka pre-fetches, this position is ahead of what was actually
processed, silently skipping records on restart.

Fix: compute the max offset per TopicPartition from the batch exchanges
and explicitly recordOffset + commit for each partition, so only the
offsets of actually-processed records are committed.

Signed-off-by: Claus Ibsen <davsclaus@apache.org>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Claus Ibsen <claus.ibsen@gmail.com>
@github-actions

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.

@gnodet gnodet 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.

Correct fix. The old commitManager.commit() (no-arg) committed the Kafka consumer's current position, which can be ahead of what was actually delivered to the processor due to Kafka's internal pre-fetching. On restart, unprocessed records between the last batch and the committed position would be silently lost.

The fix correctly:

  1. computeBatchOffsets() extracts max offset per TopicPartition from the actual exchange headers (TOPIC, PARTITION, OFFSET) using offsets.merge(tp, offset, Math::max) — only what was actually in the batch
  2. commitBatchOffsets() does explicit recordOffset() + commit(partition) per partition — mirroring how the streaming facade commits

Both the onComplete() and breakOnFirstError paths in CommitSynchronization are updated. The CommitSynchronization constructor now captures the batch offsets at creation time, ensuring the offsets are fixed before the processor runs (correct snapshot semantics).

Reviewed with Claude Code on behalf of gnodet. This review was generated by an AI agent and may contain inaccuracies; please verify all suggestions before applying.

@github-actions

Copy link
Copy Markdown
Contributor

🧪 CI tested the following changed modules:

  • components/camel-kafka

🔬 Scalpel shadow comparison — Scalpel: 9 tested, 29 compile-only — current: 9 all tested

Maveniverse Scalpel detected 38 affected modules (current approach: 9).

⚠️ Modules only in Scalpel (29)
  • apache-camel
  • camel-allcomponents
  • camel-catalog
  • camel-catalog-console
  • camel-catalog-lucene
  • camel-catalog-maven
  • camel-catalog-suggest
  • camel-componentdsl
  • camel-csimple-maven-plugin
  • 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
  • docs
  • dummy-component

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

Modules Scalpel would test (9)
  • camel-jbang-mcp
  • camel-jbang-plugin-mcp
  • camel-jbang-plugin-route-parser
  • camel-jbang-plugin-tui
  • camel-jbang-plugin-validate
  • camel-kafka
  • camel-launcher-container
  • camel-yaml-dsl-validator
  • camel-yaml-dsl-validator-maven-plugin
Modules with tests skipped (29)
  • apache-camel
  • camel-allcomponents
  • camel-catalog
  • camel-catalog-console
  • camel-catalog-lucene
  • camel-catalog-maven
  • camel-catalog-suggest
  • camel-componentdsl
  • camel-csimple-maven-plugin
  • 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
  • docs
  • dummy-component

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

⚠️ Some tests are disabled on GitHub Actions (@DisabledIfSystemProperty(named = "ci.env.name")) and require manual verification:

  • components/camel-kafka: 2 test(s) disabled on GitHub Actions
All tested modules (38 modules)
  • Camel :: All Components Sync point
  • Camel :: Assembly
  • Camel :: Catalog :: CSimple Maven Plugin (deprecated)
  • Camel :: Catalog :: Camel Catalog
  • Camel :: Catalog :: Camel Report Maven Plugin
  • Camel :: Catalog :: Camel Route Parser
  • Camel :: Catalog :: Console
  • Camel :: Catalog :: Dummy Component
  • Camel :: Catalog :: Lucene (deprecated)
  • Camel :: Catalog :: Maven
  • Camel :: Catalog :: Suggest
  • Camel :: Component DSL
  • Camel :: Coverage
  • Camel :: Docs
  • Camel :: Endpoint DSL
  • Camel :: Endpoint DSL :: Support
  • Camel :: Integration Tests
  • Camel :: JBang :: Core
  • Camel :: JBang :: Integration tests
  • Camel :: JBang :: MCP
  • Camel :: JBang :: Main
  • Camel :: JBang :: Plugin :: Edit
  • Camel :: JBang :: Plugin :: Generate
  • Camel :: JBang :: Plugin :: Kubernetes
  • Camel :: JBang :: Plugin :: MCP
  • Camel :: JBang :: Plugin :: Route Parser
  • Camel :: JBang :: Plugin :: TUI
  • Camel :: JBang :: Plugin :: Testing
  • Camel :: JBang :: Plugin :: Validate
  • Camel :: Kafka
  • Camel :: Kamelet Main
  • Camel :: Launcher
  • Camel :: Launcher :: Container
  • Camel :: YAML DSL
  • Camel :: YAML DSL :: Deserializers
  • Camel :: YAML DSL :: Maven Plugins
  • Camel :: YAML DSL :: Validator
  • Camel :: YAML DSL :: Validator Maven Plugin

⚙️ View full build and test results

@davsclaus davsclaus added this to the 4.22.0 milestone Jul 14, 2026
@davsclaus davsclaus self-assigned this Jul 14, 2026
@davsclaus davsclaus added the bug Something isn't working label Jul 14, 2026
@davsclaus
davsclaus merged commit aa1cec2 into main Jul 14, 2026
5 checks passed
@davsclaus
davsclaus deleted the fix/CAMEL-23994-batching-overcommit branch July 14, 2026 16:17
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.

2 participants