Regard new feature of Kafka aimed for negative acknowledgement and now supported by Spring-Kafka, according to /spring-kafka/docs/2.4.4.RELEASE/
"... Starting with version 2.3, the Acknowledgment interface has two additional methods nack(long sleep) and nack(int index, long sleep). The first one is used with a record listener, the second with a batch listener. Calling the wrong method for your listener type will throw an IllegalStateException.
...
With a record listener, when nack() is called, any pending offsets are committed, the remaing records from the last poll are discarded, and seeks are performed on their partitions so that the failed record and unprocessed records are redelivered on the next poll(). The consumer thread can be paused before redelivery, by setting the sleep argument. This is similar functionality to throwing an exception when the container is configured with a SeekToCurrentErrorHandler. "
Well, if some error happens on consumer side, say fail to save on database, let's say the consumer doesn't acknowledgment.acknowledge(), as far as I understand the message is still on poll and it will be read/consumed again. I guess someone can say that with nack(..., some time) the consumer can sleep giving the chance to read/consume again a bit later and don't face error. If keep listening the topic isn't an issue, my straight question is:
is there any further point on using nack instead of simply not acknowledge?
As far as I can see the message will keep in pool for the time longer than the nack sleep anywhay. So, by the way, if the consumer keeps trying get the message and save the message it will successed assuming the issue is fixed in less than sleep time.
A surrounding point or advantage would be that somehow the producer get notified that nack is used. If so, I could find some worth on it in some specific scenarios. Let's say while using Log Compation (interested only on last message status) or Kafka as a long-term storage service (future releases will provide this I guess - KIP 405)
Regard more general exceptions I tend to follow approaches like configure a SeekToCurrentErrorHandler and throw the exception