Skip to content

Fix replayed DLQ messages stuck in ancillary store as Incoming#2335

Merged
jeremydmiller merged 2 commits intomainfrom
fix/2318-ancillary-store-dlq-sticky
Mar 22, 2026
Merged

Fix replayed DLQ messages stuck in ancillary store as Incoming#2335
jeremydmiller merged 2 commits intomainfrom
fix/2318-ancillary-store-dlq-sticky

Conversation

@jeremydmiller
Copy link
Copy Markdown
Member

Closes #2318

Summary

When a message routed to an ancillary store fails and goes to the dead letter queue, replaying it from the DLQ would mark it as processed in the main store instead of the ancillary store. This left the envelope permanently stuck with Incoming status in the ancillary database tables.

Root Cause

In RecoverIncomingMessagesCommand.ExecuteAsync(), envelopes loaded from an ancillary store's inbox via LoadPageOfGloballyOwnedIncomingAsync() had their Store property set to null. When DelegatingMessageInbox.MarkIncomingEnvelopeAsHandledAsync() checked envelope.Store?.Inbox, it fell back to _inner (the main store's inbox) because Store was null.

Fix

Set envelope.Store to the store the envelope was loaded from during recovery:

foreach (var envelope in envelopes)
{
    envelope.Store ??= _store;
}

This ensures the envelope maintains its affinity to the correct store throughout its lifecycle, so DelegatingMessageInbox routes the "mark as handled" operation to the ancillary store.

Test plan

  • Failing test Bug_2318_ancillary_dlq_replay.replayed_dlq_message_should_not_be_stuck_in_incoming reproduces the issue
  • Test passes after the fix
  • Solution compiles cleanly

🤖 Generated with Claude Code

jeremydmiller and others added 2 commits March 22, 2026 12:25
)

Reproduces the bug where replayed dead letter messages from an ancillary
store are marked as processed in the main store instead, leaving them
stuck with Incoming status in the ancillary store.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When envelopes are recovered from an ancillary message store's inbox
(e.g., after DLQ replay), set envelope.Store to the store they were
loaded from. Without this, the Store property is null and
DelegatingMessageInbox falls back to the main store when marking the
envelope as handled — leaving it permanently stuck as "Incoming" in the
ancillary store.

Closes #2318

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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.

Replayed Dead Letter messages from Ancillary Store are marked as processed in the Main Store

1 participant