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 d160a2edcd14 CAMEL-23994: Fix pollOnError seek skipping messages on 
all partitions
d160a2edcd14 is described below

commit d160a2edcd14faa5045d8ba687bc5a9f7403e98d
Author: Claus Ibsen <[email protected]>
AuthorDate: Tue Jul 14 18:15:03 2026 +0200

    CAMEL-23994: Fix pollOnError seek skipping messages on all partitions
    
    When an exception was caught in the poll loop, SeekUtil.seekToNextOffset
    was called with a hardcoded offset of -1, causing it to seek
    position+1 on ALL assigned partitions. This silently dropped one
    unread message per partition, even for partitions unrelated to the error.
    
    Now SeekUtil uses the exception itself: for RecordDeserializationException
    (poison message), it seeks only the affected partition to the failing
    offset+1. For other exceptions (transient errors, commit failures),
    no positions are advanced since the error may not be record-related.
    
    Closes #24687
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
---
 .../consumer/errorhandler/BridgeErrorStrategy.java |  2 +-
 .../errorhandler/DiscardErrorStrategy.java         |  2 +-
 .../kafka/consumer/errorhandler/SeekUtil.java      | 40 ++++++----------------
 3 files changed, 13 insertions(+), 31 deletions(-)

diff --git 
a/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/consumer/errorhandler/BridgeErrorStrategy.java
 
b/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/consumer/errorhandler/BridgeErrorStrategy.java
index 098d8d10a362..52d75be21343 100644
--- 
a/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/consumer/errorhandler/BridgeErrorStrategy.java
+++ 
b/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/consumer/errorhandler/BridgeErrorStrategy.java
@@ -48,7 +48,7 @@ public class BridgeErrorStrategy implements 
PollExceptionStrategy {
         // use bridge error handler to route with exception
         recordFetcher.getBridge().handleException(exception);
         // skip this poison message and seek to the next message
-        SeekUtil.seekToNextOffset(consumer, partitionLastOffset);
+        SeekUtil.seekToNextOffset(consumer, exception);
 
         if (exception instanceof AuthenticationException || exception 
instanceof AuthorizationException) {
             continueFlag = false;
diff --git 
a/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/consumer/errorhandler/DiscardErrorStrategy.java
 
b/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/consumer/errorhandler/DiscardErrorStrategy.java
index 46c61b92d9ee..875ba83b394f 100644
--- 
a/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/consumer/errorhandler/DiscardErrorStrategy.java
+++ 
b/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/consumer/errorhandler/DiscardErrorStrategy.java
@@ -40,6 +40,6 @@ public class DiscardErrorStrategy implements 
PollExceptionStrategy {
         LOG.warn("Requesting the consumer to discard the message and continue 
to the next based on polling exception strategy");
 
         // skip this poison message and seek to the next message
-        SeekUtil.seekToNextOffset(consumer, partitionLastOffset);
+        SeekUtil.seekToNextOffset(consumer, exception);
     }
 }
diff --git 
a/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/consumer/errorhandler/SeekUtil.java
 
b/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/consumer/errorhandler/SeekUtil.java
index b3c6e77adc12..5ed7021cae0c 100644
--- 
a/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/consumer/errorhandler/SeekUtil.java
+++ 
b/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/consumer/errorhandler/SeekUtil.java
@@ -17,10 +17,9 @@
 
 package org.apache.camel.component.kafka.consumer.errorhandler;
 
-import java.util.Set;
-
 import org.apache.kafka.clients.consumer.Consumer;
 import org.apache.kafka.common.TopicPartition;
+import org.apache.kafka.common.errors.RecordDeserializationException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -31,33 +30,16 @@ final class SeekUtil {
 
     }
 
-    public static void seekToNextOffset(Consumer<?, ?> consumer, long 
partitionLastOffset) {
-        boolean logged = false;
-        Set<TopicPartition> tps = consumer.assignment();
-        if (tps != null && partitionLastOffset != -1) {
-            long next = partitionLastOffset + 1;
-
-            for (TopicPartition tp : tps) {
-                if (LOG.isInfoEnabled()) {
-                    LOG.info(
-                            "Consumer seeking to next offset {} to continue 
polling next message from topic {} on partition {}",
-                            next, tp.topic(), tp.partition());
-                }
-
-                consumer.seek(tp, next);
-            }
-        } else if (tps != null) {
-            for (TopicPartition tp : tps) {
-                long next = consumer.position(tp) + 1;
-                if (!logged) {
-                    LOG.info(
-                            "Consumer seeking to next offset {} to continue 
polling next message from topic {} on partition {}",
-                            next,
-                            tp.topic(), tp.partition());
-                    logged = true;
-                }
-                consumer.seek(tp, next);
-            }
+    public static void seekToNextOffset(Consumer<?, ?> consumer, Exception 
exception) {
+        if (exception instanceof RecordDeserializationException rde) {
+            TopicPartition tp = rde.topicPartition();
+            long next = rde.offset() + 1;
+            LOG.info("Consumer seeking to next offset {} to skip poison 
message on topic {} partition {}",
+                    next, tp.topic(), tp.partition());
+            consumer.seek(tp, next);
+        } else {
+            LOG.warn("Non-record exception caught during poll, not advancing 
any partition offsets: {}",
+                    exception.getMessage());
         }
     }
 }

Reply via email to