AckMode.MANUAL hands the commit decision to your listener.
@Bean
ConcurrentKafkaListenerContainerFactory<String, String> factory(...) {
var f = new ConcurrentKafkaListenerContainerFactory<String, String>();
f.getContainerProperties().setAckMode(ContainerProperties.AckMode.MANUAL);
return f;
}
@KafkaListener(topics = "orders")
void onOrder(String payload, Acknowledgment ack) {
process(payload);
ack.acknowledge(); // only now is the offset committed
}
An exception before acknowledge() means the record is redelivered,
which is the behaviour at-least-once processing depends on.
Run this yourself in the Online Java Compiler, spin up a live REST API in the API Sandbox, or practise with Java interview questions.
Published 2026-08-11