A basic Spring Kafka application that showcases the Spring framework features and behavior around Kafka error handling.
Spring for Apache Kafka (https://spring.io/projects/spring-kafka) has a significant amount of software machinery around error handling (relevant section in docs). This project aims to de-mystify and illuminate it. Let's learn something!
Follow these instructions to get up and running with a Kafka broker and the example program.
- Pre-requisites: Java, Kafka and kcat
- I used Java 21 installed via SDKMAN.
- I used Kafka 3.8.0 installed via Homebrew.
- I used kcat 1.7.0 installed via Homebrew.
- Tip: check your HomeBrew-installed package versions with a command like the following.
-
brew list --versions kafka
- Running the application and the test cases depend on a locally running Kafka instance. Use the
startKafkaandstopKafkacommands (seecommands.sh) to run Kafka. Specifically, use the following commands to source thecommands.shfile and then start a Kafka broker.-
. commands.sh -
startKafka
-
- In a new terminal, build and run the program with:
-
build && run
-
- In a new terminal, produce some test data with:
-
produceValidMessage
- You should see the application react with new logs.
-
- In a new terminal, produce some test data with:
-
produceInvalidMessage
- You should see the application react with new logs.
-
- Consume the dead letter topic with:
-
consumeDeadLetterTopic
- You should see all the "invalid" messages there. As new "invalid" messages are received by the app, they will be forwarded to this topic.
-
- Stop all components
- When you are done, stop the dead letter topic Kafka consumer.
- Stop the application.
- Finally, stop the Kafka broker with the following command.
-
stopKafka
Source the commands.sh file using source commands.sh which will load your shell with useful
commands. Commands include:
startKafkastart KafkastopKafkastop Kafkabuildbuild (without tests)runrun the appproduceValidMessageproduce a test JSON message to themy-messagesKafka topicproduceInvalidMessageproduce a test JSON message to themy-messagesKafka topic that has a field of the wrong type JSON that the app is expectingconsumeDeadLetterTopicconsume from the Kafka topic
Warning: here is some editorialization! Is Spring for Apache Kafka fundamentally oriented to "one-message-at-a-time" processing?
The framework has a great configuration story for apps with a single consumer (there is exactly one
spring.kafka.consmer config block), for a single cluster, and for single (non-batch) message processing flows. There
is a sophisticated retry/recovery feature set. But it is restricted to the non-batch style. See this comment:
A retry adapter is not provided for any of the batch message listeners, because the framework has no knowledge of where in a batch the failure occurred. If you need retry capabilities when you use a batch listener, we recommend that you use a RetryTemplate within the listener itself. -- https://docs.spring.io/spring-kafka/docs/2.5.1.RELEASE/reference/html/#retrying-deliveries
General clean-ups, TODOs and things I wish to implement for this project:
- DONE Upgrade to Spring Boot 3.x and in so doing, upgrade to a later version of Spring for Apache Kafka.
- There is a Spring Boot 3.x migration guide here. One of the main things that stand out to me is to use the "properties migration" dependency
- What is the migration story of Spring for Apache Kafka? Update, well there isn't a change history entry for 3.0 but
there is one for 2.9 and I'm hopeful it will
explain some of the breaking changes. Update: well it didn't totally help but I was able to easily find that the
SeektoCurrentErrorHandlerwas superseded by theDefaultErrorHandlerwith a simpleCmd + Fsearch. Nice! Also I there is another nice migration guide about the deprecatedErrorHandlerinterface.