Repository navigation
GH-5236 Kafka DeferAsync no longer re-enters the receiver inline - #5240
Merged
Merged
Conversation
KafkaListener and KafkaTopicGroupListener implemented DeferAsync() by calling _receiver.ReceivedAsync() directly. A durable receiver whose inbox write keeps failing defers from inside its own receive, so receive -> fail -> defer -> receive recursed until the process died of a stack overflow (a latched receiver looped the same way through its defer block). A deferred envelope now goes back to the receiver on its own task after a short pause (KafkaDeferredRedelivery.Delay, 1 second), and only while the listener is still running. Once the listener stops, including a pause for inbox recovery, the envelope is left alone: its offset was never completed, so the committed position can't move past it and the restarted consumer reads it again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DCggXgxnG3EBXoR9rrq37U
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #5236
Problem
KafkaListener.DeferAsync()(andKafkaTopicGroupListener's) called_receiver.ReceivedAsync()directly. When the durable inbox write keeps failing,DurableReceiver.receiveOneAsyncsettles the delivery by deferring it, from inside its own receive, so the cycle in the reported stack trace never unwinds:The process dies of a stack overflow (exit 139). A latched receiver loops the same way through its
_deferBlock. The loop also kept the receiver busy, which got in the way of the drain thatPauseForInboxRecoveryAsyncruns.Fix
New
KafkaDeferredRedelivery, used by both Kafka listeners:DeferAsyncreturns at once. The envelope goes back to the receiver on its own task, after a short pause (KafkaDeferredRedelivery.Delay, 1 second, internal), so the stack can't grow and a receiver that keeps deferring can't spin.KafkaOffsetCommitterwatermark keeps the committed position below it and the restarted consumer reads it again. Offsets never move past a message that wasn't persisted.Behavior note: Kafka has no native requeue, so
Requeueerror policies go through this same path and now redeliver after about 1 second instead of immediately.Tests
deferred_redelivery_does_not_recurse_5236(broker-free): a receiver that defers every envelope, as the failing inbox does. The stack depth stays flat across 20 redeliveries,DeferAsyncdoesn't wait for the redelivery, and nothing is redelivered after the listener stops.duplicate_message_handling_with_postgres_inbox,durable_topic_group_batching_4026,disable_requeueing,commit_strategy_end_to_end, compliance suites: 70/70.wolverine.slnx -c Release -f net9.0build is clean.🤖 Generated with Claude Code
https://claude.ai/code/session_01DCggXgxnG3EBXoR9rrq37U