You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
feat(durable-messaging): add envelope and routing contracts - #11282
Durable Messaging needs shared envelope, routing and handler contracts so inbox, outbox and hosting can be reviewed as focused layers.
Solution
Provide serialized envelopes, hierarchical correlation keys, delivery outcomes, validated options, inbox/outbox interfaces and typed handler-routing helpers in the eventual Microsoft.Orleans.DurableMessaging assembly.
Outgoing messages use explicit preparation before shared state changes. IDurableOutbox.PrepareSendAsync(IReadOnlyList<DurableEnvelope>, CancellationToken) copies and validates outgoing intents and acquires their durable wakeup prerequisite. It returns an opaque, activation-local IPreparedOutboxBatch : IDisposable; synchronous Send(IPreparedOutboxBatch) stages the prepared output.
Handlers use PrepareAsync -> ValueTask<Action>: await preparation through context.Outbox, then apply complete business mutations and send the batch from the matching synchronous action. Ordinary callers await each preparation and retain/dispose its batch through the mutation and ordinary journal-write scope. Runtime layers own started acquisitions, late results, actual persistence outcomes and delivery eligibility. Duplicate sends coalesce within their valid scope; caller cancellation preserves owned scheduling through completion.
Rationale and scope
Preparation, synchronous safe-to-commit updates and ordinary atomic journal writes keep application policy with its owner. The Journaling foundation retains its established public API and capture/replay/reset/acknowledgement protocol. A failed initial recovery completes that attempt with its original error and leaves the manager uninitialized. A subsequent explicit InitializeAsync resets and replays the existing instances from the beginning; writes become available after successful recovery. One lifetime work-loop task handles recovery attempts and persistence. After a failed attempt, that same task waits for a queued explicit initialization request; stale signals are consumed while it waits. Initialization admission and owner shutdown are serialized under the manager lock. Registration stays closed after initialization begins, and admitted persistence failures retain terminal handling. Feature owners handle failed writes and cleanup directly. Deletion follows the explicit owner workflow: stop and drain messaging, await actual journal deletion, then dispose or deactivate; subsequent work uses a fresh owner.
This intermediate project stays non-packable while runtime and hosting are assembled. Envelope aliases/member IDs, routing, payload metadata and the DeliverAsync wire manifest are preserved. Contract tests retain the external-consumer boundary and exercise internal adapters through public interfaces and reflection.
Depends on #11326 at 901d42432a8e7daa1308aa7a232f02e3f1adc67a, based on selected main 0bfd95e8561699b3bb7c619b0b0d2378d84395bc. Published head: fb911fa47667b91215371d9f43298c5178619de0; all eleven contracts commits remain equivalent. Review the immutable incremental diff. Inbox, outbox and final composition follow in #11284, #11285 and #10693.
Adds observer registration. Finding: moderate (1 vote) — null observers are not validated before the compatibility default throws NotSupportedException.
The newest successful coverage run tested 8efd435, not current main a68e9ed.
Coverage combines every CI test matrix job, including providers, CodeGen, .NET 8/10, Linux, Windows, and macOS, using canonical physical source and branch identities.
The comparison remains report-only while normal line and branch variance is calibrated.
The comment uses “an segment separator”, which is grammatically incorrect and makes the validation explanation less clear; change it to “a segment separator”.
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
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.
Problem
Durable Messaging needs shared envelope, routing and handler contracts so inbox, outbox and hosting can be reviewed as focused layers.
Solution
Provide serialized envelopes, hierarchical correlation keys, delivery outcomes, validated options, inbox/outbox interfaces and typed handler-routing helpers in the eventual
Microsoft.Orleans.DurableMessagingassembly.Outgoing messages use explicit preparation before shared state changes.
IDurableOutbox.PrepareSendAsync(IReadOnlyList<DurableEnvelope>, CancellationToken)copies and validates outgoing intents and acquires their durable wakeup prerequisite. It returns an opaque, activation-localIPreparedOutboxBatch : IDisposable; synchronousSend(IPreparedOutboxBatch)stages the prepared output.Handlers use
PrepareAsync -> ValueTask<Action>: await preparation throughcontext.Outbox, then apply complete business mutations and send the batch from the matching synchronous action. Ordinary callers await each preparation and retain/dispose its batch through the mutation and ordinary journal-write scope. Runtime layers own started acquisitions, late results, actual persistence outcomes and delivery eligibility. Duplicate sends coalesce within their valid scope; caller cancellation preserves owned scheduling through completion.Rationale and scope
Preparation, synchronous safe-to-commit updates and ordinary atomic journal writes keep application policy with its owner. The Journaling foundation retains its established public API and capture/replay/reset/acknowledgement protocol. A failed initial recovery completes that attempt with its original error and leaves the manager uninitialized. A subsequent explicit
InitializeAsyncresets and replays the existing instances from the beginning; writes become available after successful recovery. One lifetime work-loop task handles recovery attempts and persistence. After a failed attempt, that same task waits for a queued explicit initialization request; stale signals are consumed while it waits. Initialization admission and owner shutdown are serialized under the manager lock. Registration stays closed after initialization begins, and admitted persistence failures retain terminal handling. Feature owners handle failed writes and cleanup directly. Deletion follows the explicit owner workflow: stop and drain messaging, await actual journal deletion, then dispose or deactivate; subsequent work uses a fresh owner.This intermediate project stays non-packable while runtime and hosting are assembled. Envelope aliases/member IDs, routing, payload metadata and the
DeliverAsyncwire manifest are preserved. Contract tests retain the external-consumer boundary and exercise internal adapters through public interfaces and reflection.Depends on #11326 at
901d42432a8e7daa1308aa7a232f02e3f1adc67a, based on selected main0bfd95e8561699b3bb7c619b0b0d2378d84395bc. Published head:fb911fa47667b91215371d9f43298c5178619de0; all eleven contracts commits remain equivalent. Review the immutable incremental diff. Inbox, outbox and final composition follow in #11284, #11285 and #10693.Microsoft Reviewers: Open in CodeFlow