Add the kafka-basics module
This commit is contained in:
79
kafka-basics/docs/06-acknowledgement.md
Normal file
79
kafka-basics/docs/06-acknowledgement.md
Normal file
@@ -0,0 +1,79 @@
|
||||
[← Consuming](05-consuming.md) · [Module README](../README.md) · [Testing →](07-testing.md)
|
||||
|
||||
# 6. Acknowledgement, and a property that is not where you look for it
|
||||
|
||||
The container's default `AckMode` is **`BATCH`**: commit the offsets of the whole `poll()` batch
|
||||
after the listener has returned for every record in it. Confirmed at runtime by
|
||||
[`EffectiveConfigTest`](../src/test/java/com/ankurm/kafkabasics/EffectiveConfigTest.java):
|
||||
|
||||
```
|
||||
=== listener container ===
|
||||
ackMode BATCH
|
||||
groupId orders-basic
|
||||
```
|
||||
|
||||
That gives at-least-once delivery. A crash after processing and before the commit redelivers the
|
||||
batch, which is why your listener must be idempotent — and why
|
||||
[the error-handling article](https://ankurm.com/spring-kafka-4-1-error-handling-dlt-retry-topics/)
|
||||
is a necessary sequel rather than an optional one.
|
||||
|
||||
## Where `enable.auto.commit` actually lives
|
||||
|
||||
This one is worth the detour, because every debugging session about commits starts in the wrong
|
||||
place.
|
||||
|
||||
- The **kafka-clients default** for `enable.auto.commit` is `true`.
|
||||
- **Spring Boot does not set it.** It is absent from `ConsumerFactory.getConfigurationProperties()`,
|
||||
before the containers start and after.
|
||||
- **`ConsumerFactory.isAutoCommit()` returns `true`** on a stock Boot 4.1 application, because it
|
||||
reads that same absent key and falls back to the client default.
|
||||
- And yet **no consumer auto-commits**, because `ListenerConsumer.determineAutoCommit` checks
|
||||
whether the factory config contains the key and, when it does not, calls
|
||||
`setProperty("enable.auto.commit", "false")` on the **per-container `Properties`** handed to
|
||||
`createConsumer`.
|
||||
|
||||
So the shared factory never learns, its public accessor answers the opposite of the truth, and
|
||||
the real value lives in an override map you cannot reach from application code. All four of
|
||||
those statements are asserted in the test, including the counter-intuitive one:
|
||||
|
||||
```java
|
||||
assertThat(this.consumerFactory.isAutoCommit()).isTrue();
|
||||
```
|
||||
|
||||
If you ever need to know whether a running consumer auto-commits, read the consumer's own
|
||||
metrics or its startup log line, not the factory.
|
||||
|
||||
## Manual acknowledgement
|
||||
|
||||
```yaml
|
||||
spring:
|
||||
kafka:
|
||||
listener:
|
||||
ack-mode: MANUAL
|
||||
```
|
||||
|
||||
```java
|
||||
@KafkaListener(topics = "orders")
|
||||
void onOrder(OrderEvent event, Acknowledgment acknowledgment) {
|
||||
process(event);
|
||||
acknowledgment.acknowledge();
|
||||
}
|
||||
```
|
||||
|
||||
Nothing commits until `acknowledge()` runs, which is what you want when the work must be durable
|
||||
before the offset moves. Two things to know:
|
||||
|
||||
- Asking for `MANUAL` while auto-commit is genuinely enabled is an
|
||||
`IllegalStateException` at container start. It does not happen on a stock configuration —
|
||||
despite `isAutoCommit()` returning `true` — because `determineAutoCommit` sets the container
|
||||
property to `false` before the check runs. [`ManualAckTest`](../src/test/java/com/ankurm/kafkabasics/ManualAckTest.java)
|
||||
pins that down, because it is exactly the kind of interaction that would otherwise be a
|
||||
surprise in production.
|
||||
- **An `Acknowledgment` you forget to call stalls the partition.** Not immediately — the
|
||||
container keeps polling until `max.poll.records` of un-acknowledged records accumulate. So the
|
||||
symptom is a consumer that works for a while and then stops, which reads like a broker problem.
|
||||
|
||||
`MANUAL_IMMEDIATE` commits synchronously on the consumer thread instead of at the end of the
|
||||
batch. It is slower and it is the right choice when redelivery is genuinely expensive.
|
||||
|
||||
[Testing →](07-testing.md)
|
||||
Reference in New Issue
Block a user