Exception Handling in Spring for Apache Kafka Streams – Part 1

To handle potential exceptions in applications using Spring for Apache Kafka Streams, you can configure the following settings:

Configuration Handles Typical examples
DESERIALIZATION_EXCEPTION_HANDLER_CLASS_CONFIG Consumer deserialization failures Invalid JSON, corrupted Avro/Protobuf, wrong Serde
PROCESSING_EXCEPTION_HANDLER_CLASS_CONFIG Exceptions thrown while processing records NullPointerException, ArithmeticException, business logic exceptions in map(), join(), filter(), etc.
PRODUCTION_EXCEPTION_HANDLER_CLASS_CONFIG Exceptions while producing output records Serialization failure, broker rejecting a record, oversized record

How exactly does that work? Let’s find out together in this tutorial!

First, I’ll create a new Maven project, similar to the example in the previous tutorial, as follows:

The dependencies related to Spring for Apache Kafka Streams will be declared as follows:

We need to declare dependency management for the Jackson libraries so that they are compatible with each other, as follows:

I also declared dependencies for the Slf4J and Logback libraries so that we can log all the errors that occur, as follows:

The configuration file for the Logback library in the /src/main/resources directory will have the following content:

You should also configure the Apache Kafka Server information and enable Kafka streams as follows:

The first thing I need to tell you is that the values ​​of the configurations DESERIALIZATION_EXCEPTION_HANDLER_CLASS_CONFIG, PROCESSING_EXCEPTION_HANDLER_CLASS_CONFIG, and PRODUCTION_EXCEPTION_HANDLER_CLASS_CONFIG are implementations for the interfaces DeserializationExceptionHandler, ProcessingExceptionHandler, and ProductionExceptionHandler, respectively.

DeserializationExceptionHandler

As mentioned above, the DeserializationExceptionHandler handles exceptions related to deserializing messages from the producer in our application.

For the implementation of the DeserializationExceptionHandler interface, the Apache Kafka Streams library supports two implementations by default:

  • LogAndContinueExceptionHandler
  • LogAndFailExceptionHandler

The Spring for Apache Kafka library also supports the implementation:

  • RecoveringDeserializationExceptionHandler

LogAndContinueExceptionHandler logs deserialization errors, ignores the faulty message, and continues processing other messages. LogAndFailExceptionHandler also logs deserialization errors but stops the application. The RecoveringDeserializationExceptionHandler implementation, instead of just logging and ignoring the faulty message, sends that message to a Dead Letter Queue (DLQ) topic so you can recover it later.

For example, I define a stream topology as follows:

This stream topology will consume topic “users” with the serialization/deserialization for the key being String and the value being the class User. The content of the class User is as follows:

Class to run the application:

Now, if you run the application and publish a message to the users topic with key “001” and value ‘{“name”:}, you will see that our application will log the deserialization error and stop, using the deserialization class LogAndFailExceptionHandler, as follows:

If you configure an exception handler for this deserialization using the LogAndContinueExceptionHandler class:

and when you run the application again, you will see that the LogAndContinueExceptionHandler class will handle the error:

It simply logs the error, and our application will continue running, guys!

ProcessingExceptionHandler

By default, the Apache Kafka Streams library supports two implementations for the ProcessingExceptionHandler interface:

  • LogAndContinueProcessingExceptionHandler
  • LogAndFailProcessingExceptionHandler

The Spring for Apache Kafka library also supports the implementation:

  • RecoveringProcessingExceptionHandler

Similar to DeserializationExceptionHandler, LogAndContinueProcessingExceptionHandler will log deserialization errors, ignore the faulty message, and continue processing other messages. LogAndFailProcessingExceptionHandler will log deserialization errors but will stop the application, and RecoveringProcessingExceptionHandler will log the error and send the message to a Dead Letter Queue (DLQ) topic so you can recover it later.

For example, I have a stream topology as follows:

If you now run the application and publish a message with key “001” and value “ERROR”, you will see the application log the error using the LogAndFailProcessingExceptionHandler class and stop as follows:

You can change the exception handler class in this case using the PROCESSING_EXCEPTION_HANDLER_CLASS_CONFIG configuration as follows:

Run the example again and republish the message with the content as above. You will see that our application will still log the error, but it will no longer stop.

You can read part 2 here.

You can see all the exception handlers in the video here:

Add Comment