Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixes #656 Fixes #657 Previously, after a rollback, we only performed a `seek` on the failed record. We need to seek for all unprocessed records. Also, when no error handler was provided, and using a batch listener, the offsets were added to `acks` and incorrectly committed. (#657). Also, if a `ContainerAwareErrorHandler` "handles" the error, the offsets weren't committed. Enhance the tests to verify full seeks. Add a new test to verify the batch listener doesn't commit after a roll back. **cherry-pick to 2.1.x, 2.0.x** I will backport to 1.3.x after review. * Some simple polishing * Remove `@FunctionalInterface` since it's not for Java 7 * Refactor `DefaultAfterRollbackProcessor` to avoid extra loop
- Loading branch information
1 parent
877fd6a
commit e826a58
Showing
9 changed files
with
295 additions
and
60 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
48 changes: 48 additions & 0 deletions
48
spring-kafka/src/main/java/org/springframework/kafka/listener/AfterRollbackProcessor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/* | ||
* Copyright 2018 the original author or authors. | ||
* | ||
* Licensed 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.springframework.kafka.listener; | ||
|
||
import java.util.List; | ||
|
||
import org.apache.kafka.clients.consumer.Consumer; | ||
import org.apache.kafka.clients.consumer.ConsumerRecord; | ||
|
||
/** | ||
* Invoked by a listener container with remaining, unprocessed, records | ||
* (including the failed record). Implementations should seek the desired | ||
* topics/partitions so that records will be re-fetched on the next | ||
* poll. When used with a batch listener, the entire batch of records is | ||
* provided. | ||
* | ||
* @param <K> the key type. | ||
* @param <V> the value type. | ||
* | ||
* @author Gary Russell | ||
* | ||
* @since 1.3.5 | ||
* | ||
*/ | ||
public interface AfterRollbackProcessor<K, V> { | ||
|
||
/** | ||
* Process the remaining records. | ||
* @param records the records. | ||
* @param consumer the consumer. | ||
*/ | ||
void process(List<ConsumerRecord<K, V>> records, Consumer<K, V> consumer); | ||
|
||
} |
63 changes: 63 additions & 0 deletions
63
...kafka/src/main/java/org/springframework/kafka/listener/DefaultAfterRollbackProcessor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/* | ||
* Copyright 2018 the original author or authors. | ||
* | ||
* Licensed 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.springframework.kafka.listener; | ||
|
||
import java.util.HashSet; | ||
import java.util.List; | ||
import java.util.Set; | ||
|
||
import org.apache.commons.logging.Log; | ||
import org.apache.commons.logging.LogFactory; | ||
import org.apache.kafka.clients.consumer.Consumer; | ||
import org.apache.kafka.clients.consumer.ConsumerRecord; | ||
import org.apache.kafka.common.TopicPartition; | ||
|
||
/** | ||
* Default implementation of {@link AfterRollbackProcessor}. Seeks all | ||
* topic/partitions so the records will be re-fetched, including the failed | ||
* record. | ||
* | ||
* @param <K> the key type. | ||
* @param <V> the value type. | ||
* | ||
* @author Gary Russell | ||
* @author Artem Bilan | ||
* | ||
* @since 1.3.5 | ||
* | ||
*/ | ||
public class DefaultAfterRollbackProcessor<K, V> implements AfterRollbackProcessor<K, V> { | ||
|
||
private static final Log logger = LogFactory.getLog(DefaultAfterRollbackProcessor.class); | ||
|
||
@Override | ||
public void process(List<ConsumerRecord<K, V>> records, Consumer<K, V> consumer) { | ||
Set<TopicPartition> seekOffsets = new HashSet<>(); | ||
for (ConsumerRecord<K, V> record : records) { | ||
TopicPartition topicPartition = new TopicPartition(record.topic(), record.partition()); | ||
if (seekOffsets.add(topicPartition)) { | ||
try { | ||
consumer.seek(topicPartition, record.offset()); | ||
} | ||
catch (Exception e) { | ||
logger.error("Failed to seek " + topicPartition + " to " + record.offset()); | ||
} | ||
} | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.