Add the kafka-error-handling module
This commit is contained in:
59
kafka-error-handling/README.md
Normal file
59
kafka-error-handling/README.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# `kafka-error-handling` — retries, DLT and poison pills
|
||||
|
||||
Companion project for
|
||||
[**Kafka Error Handling with Spring Kafka 4.1: DLT, Retry Topics and Poison Pills**](https://ankurm.com/spring-kafka-4-1-error-handling-dlt-retry-topics/)
|
||||
on ankurm.com.
|
||||
|
||||
Six tests against a **real Kafka broker** started in-process in KRaft mode. No Docker, no local
|
||||
install. `./scripts/run-all.sh` regenerates everything under [`docs/output/`](docs/output/).
|
||||
|
||||
## Versions
|
||||
|
||||
| | Version |
|
||||
|---|---|
|
||||
| JDK | 25 (Temurin 25.0.4.1+1) |
|
||||
| Spring Boot | 4.1.1 |
|
||||
| Spring Kafka | 4.1.1 |
|
||||
| kafka-clients | 4.2.1 (Boot-managed) |
|
||||
|
||||
## Profiles
|
||||
|
||||
| Profile | What it wires |
|
||||
|---|---|
|
||||
| `dlt` | `DefaultErrorHandler` + `DeadLetterPublishingRecoverer`, `FixedBackOff(1000, 2)`, `PermanentFailure` classified non-retryable |
|
||||
| `dltbytes` | the same, with a `byte[]`-aware template map so poison pills keep their original bytes |
|
||||
| `retrytopic` | `@RetryableTopic` non-blocking retries with a `@DltHandler` |
|
||||
| `defaults` | the stock `DefaultErrorHandler`, for reading its behaviour |
|
||||
|
||||
## Documentation
|
||||
|
||||
1. [Two kinds of failure, and why they need different machinery](docs/01-two-kinds-of-failure.md)
|
||||
2. [What the default actually does](docs/02-default-error-handler.md)
|
||||
3. [Poison pills](docs/03-poison-pills.md)
|
||||
4. [The dead-letter topic](docs/04-the-dlt.md)
|
||||
5. [Non-blocking retries with `@RetryableTopic`](docs/05-retryable-topic.md)
|
||||
|
||||
## Captured output
|
||||
|
||||
| File | Shows |
|
||||
|---|---|
|
||||
| [`default-backoff.txt`](docs/output/default-backoff.txt) | ten deliveries, zero delay |
|
||||
| [`retry-and-dlt.txt`](docs/output/retry-and-dlt.txt) | measured back-off and the DLT headers |
|
||||
| [`poison-pill.txt`](docs/output/poison-pill.txt) | base64 payload, and the byte-aware fix |
|
||||
| [`retry-topics.txt`](docs/output/retry-topics.txt) | the non-blocking delivery trace |
|
||||
| [`tests.txt`](docs/output/tests.txt) | 6 tests |
|
||||
|
||||
## Six things this module exists to prove
|
||||
|
||||
1. **The default is ten deliveries, zero milliseconds apart, then the record is dropped.** Not
|
||||
"retry with backoff", and not "dead-letter".
|
||||
2. **The DLT suffix is `-dlt`, not `.DLT`.** Get it wrong and the recoverer logs a WARN and the
|
||||
record is lost — your safety net silently drops it.
|
||||
3. **`kafka_dlt-exception-fqcn` is always `ListenerExecutionFailedException`** for listener
|
||||
failures. The useful header is `-exception-cause-fqcn`.
|
||||
4. **A poison pill reaches the DLT base64-encoded**, because the recoverer reuses the JSON
|
||||
producer. A per-type template map fixes it; the module shows both transcripts.
|
||||
5. **`@RetryableTopic` names retry topics by delay** — `-retry-500`, `-retry-1000` — so changing
|
||||
the multiplier renames them.
|
||||
6. **`@Backoff` from spring-retry no longer exists here.** Spring Kafka 4 ships its own
|
||||
`@BackOff`, and the attribute is `backOff`.
|
||||
Reference in New Issue
Block a user