Fix unobserved task exceptions when pending messages overflow (#2272)

Observe packet task failures to prevent unobserved overflow exceptions

Server dispatch and session enqueue operations create packet bus items without
waiting for delivery. When the pending-message queue overflows, Fail faults
the item's completion task, which can later raise UnobservedTaskException
even if the application handles the dropped-message notification.

Observe the completion task's exception inside MqttPacketBusItem.Fail. This
keeps the task faulted and preserves the original exception for existing and
future WaitAsync callers, including DeliverApplicationMessageAsync.

Add a garbage-collection regression test for failures without a waiter and
verify that requesting the task before or after failure preserves the original
overflow exception. Re-enable unobserved-exception tracking in the existing
overflow integration tests for both drop strategies.

Before the fix, the focused run failed the new unobserved-exception test and
both enqueue overflow tests. After the fix, all nine focused cases and all
489 tests in the .NET 10 Release test suite pass.

Fixes https://github.com/dotnet/MQTTnet/issues/2271
This commit is contained in:
Jochen Kühner
2026-09-30 20:23:57 +02:00
committed by GitHub
parent 18731d9f02
commit 483447e783
3 changed files with 70 additions and 3 deletions
@@ -48,7 +48,7 @@ public sealed class Injection_Tests : BaseTestClass
[TestMethod]
public async Task Enqueue_Application_Message_At_Session_Level_QueueOverflow_DropNewMessageStrategy()
{
using var testEnvironment = CreateTestEnvironment(trackUnobservedTaskException: false);
using var testEnvironment = CreateTestEnvironment();
var server = await testEnvironment.StartServer(
builder => builder
@@ -126,7 +126,7 @@ public sealed class Injection_Tests : BaseTestClass
[TestMethod]
public async Task Enqueue_Application_Message_At_Session_Level_QueueOverflow_DropOldestQueuedMessageStrategy()
{
using var testEnvironment = CreateTestEnvironment(trackUnobservedTaskException: false);
using var testEnvironment = CreateTestEnvironment();
var server = await testEnvironment.StartServer(
builder => builder
@@ -322,7 +322,7 @@ public sealed class Injection_Tests : BaseTestClass
[TestMethod]
public async Task Deliver_Application_Message_At_Session_Level_QueueOverflow_DropOldestQueuedMessageStrategy()
{
using var testEnvironment = CreateTestEnvironment(trackUnobservedTaskException: false);
using var testEnvironment = CreateTestEnvironment();
var server = await testEnvironment.StartServer(
builder => builder