Skip to content

GH-4328: Expose native Kafka Streams DLQ configuration#4360

Merged
sobychacko merged 1 commit into
spring-projects:mainfrom
loicgreffier:GH-4328
Mar 31, 2026
Merged

GH-4328: Expose native Kafka Streams DLQ configuration#4360
sobychacko merged 1 commit into
spring-projects:mainfrom
loicgreffier:GH-4328

Conversation

@loicgreffier

@loicgreffier loicgreffier commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

The PR addresses the 4 points mentioned in issue #4328:

  • Make the RecoveringDeserializationExceptionHandler leverage the new Kafka Streams native DLQ introduced by KIP-1034.
  • Introduce a new NativeDeadLetterDestinationResolver as an alternative to resolve the Kafka Streams native DLQ destination.
  • Make the Kafka Streams native DLQ use the Spring Kafka DLT headers.
  • Introduce new RecoveringProcessingExceptionHandler and RecoveringProductionExceptionHandler.

To answer these points:

  • New DeadLetterRecordManager class. I've introduced a new DeadLetterRecordManager class as a common place to build DLT headers, so the utilities for building headers can be leveraged by both the DeadLetterPublishingRecoverer and exception handlers. I preferred this over a static utility class because of the number of parameters. One instance per handler and for the DeadLetterPublishingRecoverer.

  • New RecoveringProcessingExceptionHandler and RecoveringProductionExceptionHandler implementations with the same recovery logic as RecoveringDeserializationExceptionHandler. I've introduced a new AbstractRecoveringExceptionHandler that holds the commons for all handlers.

  • New NativeDeadLetterDestinationResolver interface. Allow users to define a native DLQ routing logic based on 3 given parameters: the ErrorHandlerContext, the source record as ConsumerRecord and the exception. All handlers leverage it. For now, it is loaded in the same way as the DeadLetterPublishingRecoverer was.

  • I’ve updated the tests to cover the 3 recovering handler implementations. I introduced an AbstractRecoveringExceptionHandlerTests class that contains commons tests. Child classes override some methods to create the corresponding handler and assert the related handling response.

Concerns:

  • The HeaderNames class is still located within the DeadLetterPublishingRecoverer class. It might be better to move it to DeadLetterRecordManager, but this would be a breaking change.

Closes #4328

@loicgreffier loicgreffier force-pushed the GH-4328 branch 8 times, most recently from 6c94761 to a0db242 Compare March 22, 2026 21:14
@sobychacko

Copy link
Copy Markdown
Contributor

@loicgreffier Many thanks for the draft PR. I added some initial feedback that I wanted to convey. Please take a look and see what you think. Overall, the PR looks great. Some general things to keep in mind - we need to add a reference docs section for this (and some javadoc comments - see my inline comments). We also need a new entry in the whats-new section. Thanks!

@loicgreffier loicgreffier force-pushed the GH-4328 branch 8 times, most recently from 8411197 to 6ec0036 Compare March 26, 2026 23:05
Comment thread spring-kafka-docs/src/main/antora/modules/ROOT/pages/whats-new.adoc
Comment thread spring-kafka-docs/src/main/antora/modules/ROOT/pages/streams.adoc Outdated
Comment thread spring-kafka-docs/src/main/antora/modules/ROOT/pages/whats-new.adoc Outdated
Comment thread spring-kafka-docs/src/main/antora/modules/ROOT/pages/streams.adoc Outdated
@sobychacko

Copy link
Copy Markdown
Contributor

@loicgreffier Some more minor nitpicks. Once you address those, feel free to remove the draft status on the PR.

@loicgreffier loicgreffier marked this pull request as ready for review March 27, 2026 13:26
@loicgreffier

loicgreffier commented Mar 27, 2026

Copy link
Copy Markdown
Contributor Author

@sobychacko I've removed the draft status.

Regarding the documentation:

  • I've updated the whats-new section with information about the new handlers, the activation of the native DLQ, and the deprecated property.
  • For the streams documentation:
    • I've created 3 distincts sections for RecoveringDeserializationExceptionHandler, RecoveringProcessingExceptionHandler and RecoveringProductionExceptionHandler.
    • I've added a Recovery Strategies section that explains the recovery paths and options used by all handlers. Each handler section points to this Recovery Strategies section.
    • I've added a section for the new dead-letter destination resolver.
    • I've added a section for the Kafka Streams dead-letter topic name property and the StreamsBuilderFactoryBean.

If any sentence or wording isn't clear and need to be revised, please don't hesitate to let me know.

EDIT: I've added a word about the headers that are being attached to the dead-letter record.

@loicgreffier loicgreffier force-pushed the GH-4328 branch 2 times, most recently from e4ecab1 to 4e1dc01 Compare March 27, 2026 15:25
Comment thread spring-kafka-docs/src/main/antora/modules/ROOT/pages/streams.adoc
Comment thread spring-kafka-docs/src/main/antora/modules/ROOT/pages/whats-new.adoc Outdated
Comment thread spring-kafka-docs/src/main/antora/modules/ROOT/pages/streams.adoc
@sobychacko

sobychacko commented Mar 27, 2026

Copy link
Copy Markdown
Contributor

@loicgreffier Thanks for all the updates. I added a final round of PR review comments. Hopefully, once that is addressed, we can take it for a final spin of review and merge.

Btw - can you update the commit message with some more details about the rationale for the changes. We usually follow these guidelines for commit messages: https://cbea.ms/git-commit/

Thanks!

@sobychacko

Copy link
Copy Markdown
Contributor

Could you take care of the commit message? (See my comment above). Also, please sign your commits following DCO - https://spring.io/blog/2025/01/06/hello-dco-goodbye-cla-simplifying-contributions-to-spring

@loicgreffier loicgreffier changed the title GH-4328: Add support for native Kafka Streams DLQ GH-4328: Expose native Kafka Streams DLQ configuration Mar 27, 2026
@loicgreffier loicgreffier force-pushed the GH-4328 branch 2 times, most recently from 62aa2f5 to 7f933c1 Compare March 27, 2026 21:10
Extract the DLT record header-building logic into a new DeadLetterRecordManager
class so it can be used outside of DeadLetterPublishingRecoverer.

Add two new handlers, RecoveringProcessingExceptionHandler and
RecoveringProductionExceptionHandler, to handle processing and production errors, respectively.

Add a common AbstractRecoveringExceptionHandler that centralizes
the shared error-handling logic for all provided recovering exception handlers.

Add a KafkaStreamsDeadLetterDestinationResolver to allow users to define
dead-letter routing logic used by the Kafka Streams native DLQ in the provided
exception handler implementations.

Update StreamsBuilderFactoryBean to expose a dead-letter queue topic name
as a possible destination for all provided recovering exception handler implementations.

Fixes: spring-projects#4328
Signed-off-by: Loïc Greffier <loic.greffier@michelin.com>
@loicgreffier

Copy link
Copy Markdown
Contributor Author

Commit message has been changed, accordingly to the original issue title

@sobychacko

Copy link
Copy Markdown
Contributor

@loicgreffier Thanks for the updates. I will merge the PR after some more testing and review.

@sobychacko sobychacko self-requested a review March 31, 2026 14:53
@sobychacko sobychacko merged commit fe028e4 into spring-projects:main Mar 31, 2026
3 checks passed
@sobychacko

Copy link
Copy Markdown
Contributor

@loicgreffier Thank you once again for the PR contribution! It is now merged upstream to main.

@loicgreffier

Copy link
Copy Markdown
Contributor Author

@sobychacko Many thanks, if any feedback post-merge, feel free to let me know

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Expose native Kafka Streams DLQ configuration (KIP-1034)

2 participants