Skip to content

Honor disconnect Will reasons and session lifecycle - #2266

Open
YAJeff wants to merge 1 commit into
dotnet:masterfrom
YAJeff:fix/disconnect-will-lifecycle
Open

YAJeff wants to merge 1 commit into
dotnet:masterfrom
YAJeff:fix/disconnect-will-lifecycle

Conversation

@YAJeff

@YAJeff YAJeff commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Fixes #2256.

The server currently suppresses the Will for every client DISCONNECT and every takeover, and otherwise publishes immediately without observing Will Delay. Honor DISCONNECT 0x04 and the MQTT Will lifecycle with an internal scheduler that captures each connection's Will, identity and deadline.

Only normal client DISCONNECT (0x00) suppresses the Will. Other eligible disconnects publish after the earlier of Will Delay and session expiry. Resuming the same session before that deadline cancels the pending Will; an overdue Will, clean start, or zero-delay takeover publishes the old connection's Will. Connection ownership prevents late cleanup from changing the new connection's Will. Captured message expiry begins at publication.

The scheduler dispatches outside session/state locks, owns its background task, and preserves undispatched messages if a callback stops the server. With persistent sessions, deadlines survive stop/restart of the same server instance and overdue work runs before accepting reconnects. Nonpersistent shutdown and final disposal end sessions and flush eligible Wills. This adds no durable storage or public API, and does not claim persistence across process restart.

Dependency: this PR consumes the session's existing ExpiryInterval property. Correct DISCONNECT expiry replacement, including explicit zero, and resumed CONNECT expiry require #2264. Those changes are deliberately not bundled here. Both PRs were also tested together in an isolated local checkout.

Specification:

Compatibility: normal-disconnect suppression remains; MQTT 3.1.1 takeover now publishes the old Will as required. The existing takeover test expected suppression and is corrected accordingly. Timed dispatch has 100 ms scheduling granularity. Existing persistent-session storage remains in memory.

Synthetic regressions for DISCONNECT 0x04, another nonzero reason and ignored Will Delay all fail on unmodified master 18731d9; the normal-disconnect control passes. Tests cover takeover/resume ownership, rejected and expired reconnects, expiry versus delay, deletion/timer races, retained/message-expiry fields, disabled persistence, final disposal, active/pending stop and restart, callback-triggered shutdown from timer/startup, preserved next Wills, and nonrecursive nonpersistent shutdown.

Validation:

  • All 29 focused Will/takeover cases pass on net8.0.
  • Combined with Honor DISCONNECT session expiry presence and replacement #2264: all 41 selected Will/expiry cases pass on net10.0. Separate wire probes confirm Will timing for DISCONNECT expiry zero, one, absent, and a resumed CONNECT expiry one.
  • Release solution build passed with three pre-existing benchmark deprecation warnings. Final full standalone net10.0 suite: 511 passed, zero failures.
  • Independent design and complete staged-diff reviews completed before publication; git diff --check passes.

@YAJeff

YAJeff commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

The failed CI job reports 510/511 tests passing. The failure is Concurrent_Publish_From_Multiple_Threads (ExactlyOnce): TestEnvironment.Dispose detects an unobserved MqttCommunicationException: Broken pipe from the server send loop. All Will-specific cases passed.

I reran all three concurrent-publish variants on .NET 10 locally against both unmodified master 18731d9f and this PR's unchanged head ede8eb86; both selections passed. This suggests a cleanup/timing issue, but the local Windows runs do not establish the cause of the Linux CI failure.

Could a maintainer rerun the failed test job? My API rerun request was denied with HTTP 403. Job: https://github.com/dotnet/MQTTnet/actions/runs/33817487297/job/100852725884

This branch has not been deployed

No deployments
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.

Server: DISCONNECT with DisconnectWithWillMessage reason code is ignored — Will message is not published

1 participant