perf: zero-copy receive via Body.ToMemory(); fix exception-swallowing message loss#93
Merged
Merged
Conversation
niemyjski
commented
Jun 24, 2026
niemyjski
commented
Jun 24, 2026
Per review feedback, revert the message handler's exception-handling blocks back to main so this PR is scoped to the zero-copy receive change only. Also remove the unrelated Microsoft.NET.Test.Sdk package override added to the test csproj. The only remaining change is brokeredMessage.Body.ToArray() -> ToMemory() for a zero-copy receive, which is safe for Azure Service Bus because BinaryData owns a stable buffer (not a pooled/reclaimed transport buffer).
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.
Summary
Two independent fixes to
AzureServiceBusMessageBus.OnMessageAsync:Body.ToMemory()instead ofBody.ToArray()AutoCompleteMessages = trueto permanently ack messages that failed processingCompanion to FoundatioFx/Foundatio#530 which changes
IMessage.Datafrombyte[]toReadOnlyMemory<byte>.Change 1: Zero-copy receive (
Body.ToMemory())BinaryData.ToMemory()returns aReadOnlyMemory<byte>backed by the same managed array as theBinaryData— no copy. Azure Service Bus does not pool or reclaim the body buffer after the handler returns (unlike RabbitMQ), so passing the memory directly is safe for the entire message lifetime.MemoryMarshal.TryGetArray()in the serializer extension always succeeds for array-backedReadOnlyMemory<byte>, so deserialization also remains zero-copy on this path.Change 2: Fix critical message-loss bug
Before — exceptions were caught and swallowed:
After — exceptions are rethrown:
Why this matters
With
AutoCompleteMessages = true(the SDK default):MaxDeliveryCountThe previous code swallowed all exceptions, so the handler always "returned normally" from the SDK's perspective. Any message that triggered a
MessageBusException(bad payload, type not found, etc.) or an unexpected error was silently and permanently lost — never retried, never dead-lettered.With the fix, failures trigger abandon → retry → DLQ, which is the expected behavior for any reliable message bus.