Skip to content

Remove per-message Task.Run from Service Bus deserialization - #1379

Open
Bernd Verst (berndverst) wants to merge 3 commits into
mainfrom
berndverst-issue-1376-inline-message-stream
Open

Bernd Verst (berndverst) wants to merge 3 commits into
mainfrom
berndverst-issue-1376-inline-message-stream

Conversation

@berndverst

@berndverst Bernd Verst (berndverst) commented Jul 27, 2026 •

Copy link
Copy Markdown
Member

Summary

  • return an already-completed Task<Stream> for inline Service Bus message bodies on both netstandard2.0 and net48
  • preserve the existing MemoryStream / GetBody<Stream>() behavior and leave external blob-store loading asynchronous
  • add focused cross-target tests for compressed and uncompressed round trips, observable synchronous completion, and external stream ownership

Motivation and benefits

Inline Service Bus message bodies are already in memory. Previously, deserialization used Task.Run just to wrap those bytes in a MemoryStream or retrieve the message's body stream. That operation performs no asynchronous I/O, so dispatching it to the thread pool adds a queued work item and scheduling overhead without making the underlying work asynchronous.

Returning Task.FromResult removes that unnecessary thread-pool hop for every inline message. This is especially useful when processing batches or prefetched messages: instead of queuing a burst of small work items, the caller can immediately continue with the available stream. The expected benefit is less scheduling overhead and thread-pool contention during message deserialization. This PR does not include throughput or latency benchmarks, so it does not claim a measured end-to-end performance improvement.

Compatibility

The private Task<Stream> contract is unchanged, as are the inline stream contents, initial position, and disposal lifetime. Messages stored externally still return LoadStreamAsync directly, where asynchronous I/O is needed. Compressed inline messages also avoid the stream-loading hop, but decompression may still complete asynchronously.

Tests

The tests live alongside the active project under lowercase test/DurableTask.ServiceBus.Tests, so they are included on case-sensitive filesystems as well as Windows. The external-stream ownership assertion runs inside a using scope, preserving the check that deserialization disposes the stream while guaranteeing cleanup if the test fails.

  • dotnet test test\DurableTask.ServiceBus.Tests\DurableTask.ServiceBus.Tests.csproj -f net8.0 --filter "FullyQualifiedName~ServiceBusUtilsTests"
  • dotnet test test\DurableTask.ServiceBus.Tests\DurableTask.ServiceBus.Tests.csproj -f net48 --filter "FullyQualifiedName~ServiceBusUtilsTests"

Fixes #1376

Return completed stream tasks for inline message bodies while retaining asynchronous blob-store loading. Add cross-target coverage for round trips, synchronous completion, and stream ownership.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 1347830a-17c5-4248-8e41-fee30d3066b4
Copilot AI review requested due to automatic review settings July 27, 2026 20:36
Comment thread Test/DurableTask.ServiceBus.Tests/ServiceBusUtilsTests.cs Fixed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR removes per-message Task.Run scheduling from inline Service Bus message stream loading by returning already-completed Task<Stream> instances, reducing thread-pool work-item bursts during batch deserialization.

Changes:

  • Replace Task.Run(...) with Task.FromResult(...) for inline message bodies in ServiceBusUtils.LoadMessageStreamAsync (both NETSTANDARD2_0 and net48 branches).
  • Add new unit tests intended to validate inline (compressed/uncompressed) round trips, synchronous completion for uncompressed inline messages, and async blob-store behavior/stream ownership for external messages.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/DurableTask.ServiceBus/Common/ServiceBusUtils.cs Removes thread-pool hop for inline message-body stream creation by returning completed tasks.
Test/DurableTask.ServiceBus.Tests/ServiceBusUtilsTests.cs Adds tests for inline/external deserialization behaviors, but currently placed in a directory not used by the active test project.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread test/DurableTask.ServiceBus.Tests/ServiceBusUtilsTests.cs
Move ServiceBusUtilsTests into the lowercase test project directory and ensure the external stream is disposed even if the test fails.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings September 30, 2026 00:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The focused optimization preserves existing behavior and is adequately covered across both target frameworks.

Review effort: Balanced
Findings: None

Resolved since last review (1)

Copilot AI balanced review requested due to automatic review settings September 30, 2026 00:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The optimization preserves existing behavior and is covered across both target-framework paths.

Review effort: Balanced
Findings: None

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.

Remove per-message Task.Run from Service Bus inline message deserialization

2 participants