Files
spring-messaging-demo/kafka-basics/docs/02-producing.md

68 lines
3.1 KiB
Markdown

[← The on-ramp](01-the-on-ramp.md) · [Module README](../README.md) · [Serialisation →](03-serialisation.md)
# 2. Producing, and the return value everybody throws away
[`OrderProducer`](../src/main/java/com/ankurm/kafkabasics/OrderProducer.java) has three send
methods because there are exactly three useful answers to "when do I find out this failed".
```java
public void sendAndForget(OrderEvent event) {
this.template.send(TOPIC, event.orderId(), event); // returns a CompletableFuture. Ignored.
}
```
`KafkaTemplate.send` is asynchronous and returns a `CompletableFuture<SendResult<K, V>>`.
Discarding it discards the only notification you will get. The method returns normally, the
record may never reach the broker, and nothing in your logs says so — the producer's own retry
and expiry messages are at `WARN` under `org.apache.kafka`, which most applications turn down.
This is the most common way to lose messages in a Spring Kafka application, and it looks like
correct code.
```java
this.template.send(TOPIC, event.orderId(), event)
.whenComplete((result, ex) -> { /* log, meter, compensate */ });
```
Handle the future, or block on it when the caller genuinely must not proceed without a durable
write:
```java
SendResult<String, OrderEvent> result = this.template.send(record).get();
result.getRecordMetadata().partition(); // where it landed
result.getRecordMetadata().offset(); // and at what offset
```
Blocking costs a network round trip plus the replication acknowledgement, so it belongs at the
edges of a system, not inside a loop.
## Durability comes from defaults you did not set
Spring Boot sets **nothing** on the producer beyond bootstrap servers and serializers. Here is
the effective configuration, printed by
[`EffectiveConfigTest`](../src/test/java/com/ankurm/kafkabasics/EffectiveConfigTest.java) and
committed at [`docs/output/effective-config.txt`](output/effective-config.txt):
```
property kafka-clients default set by Spring Boot
acks all -
enable.idempotence true -
retries 2147483647 -
max.in.flight.requests.per.connection 5 -
delivery.timeout.ms 120000 -
```
Since Kafka 3.0 the client defaults are `acks=all` and `enable.idempotence=true`, so a stock
Boot application already has a durable, deduplicating producer. Two consequences:
- **You do not need to set `acks=all`.** It is already on.
- **An old runbook that sets `acks=1` or `retries=0` is now a downgrade.** Those lines were
written when the defaults were weaker, and deleting them makes the system safer, which is the
opposite of how configuration usually ages.
`delivery.timeout.ms` at two minutes is the one worth revisiting: it is the total budget for a
send including retries, and a request that exceeds it fails permanently. If your future never
completes, that is the clock you are waiting on.
[Serialisation &rarr;](03-serialisation.md)