Repository navigation
feat(journaling): add state operation observers - #11280
ReubenBond wants to merge 5 commits into
Conversation
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
Two moderate correctness issues remain, along with one documentation nit.
Review effort: Lite
Findings: None
What changed in this PR
Adds durable state operation observers and grain-scoped journaling participant initialization.
Changes:
- Adds observer and participant contracts with lifecycle integration.
- Implements callback ordering, recovery fencing, and notification logging.
- Adds focused tests and regenerates the public API.
| File | Description |
|---|---|
test/Orleans.Journaling.Tests/StateManagerTests.cs |
Covers observer behavior and recovery boundaries. |
test/Orleans.Journaling.Tests/JournaledGrainParticipantTests.cs |
Covers participant initialization and activation. |
src/Orleans.Journaling/JournaledStateManager.cs |
Implements observer callbacks and recovery fencing. |
src/Orleans.Journaling/IJournaledStateObserver.cs |
Defines the observer contract. |
src/Orleans.Journaling/IJournaledStateManager.cs |
Adds observer registration. |
src/Orleans.Journaling/IJournaledGrainParticipant.cs |
Defines the participant contract. |
src/Orleans.Journaling/DurableGrain.cs |
Initializes registered participants. |
src/api/Orleans.Journaling/Orleans.Journaling.cs |
Updates generated API metadata. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Code coverage
Report-only conclusion: improved. The current-main baseline is commit 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. Coverage details |
9acb9f9 to
bdcc9c4
Compare
bdcc9c4 to
885fce7
Compare
885fce7 to
aaa76d6
Compare
30d959e to
f001c9f
Compare
f001c9f to
f1f4fd4
Compare
f1f4fd4 to
5a8cf6c
Compare
|
Superseded by the published replacement chain #11326 -> #11282 -> #11284 -> #11285 -> #10693 (final consumer head 375389b). Durable Messaging now uses asynchronous handler preparation, synchronous application, and real journaled inbox/outbox state for write readiness, capture, acknowledgement, recovery, deletion, and terminal-failure handling. Ordinary Journaling write/delete calls remain the persistence boundary. The separate observer API, registration, and consumer dependency have been removed from the replacement chain. Final integration passed all 526 cases on native .NET 8 and .NET 10 with zero failures or skips, including all 12 provider-cutover cases. Generated API, normal Release packaging, compiled snippets, and documentation validation also passed. Historical commits and checkpoints remain preserved. Closing this proposal without merging it. |

Problem
Journaled features need to prepare fallible work within the serialized write boundary, capture safe effects and completion state together, and stop outstanding external work when the journal manager is terminally fenced.
Solution and rationale
Add
IJournaledStateObserverand a backward-compatible defaultIJournaledStateManager.RegisterObserverimplementation. Unique observers register before initialization. Write/delete request guards validate each caller before admission; the work loop awaits all write preparations, then all finalizations, then runs start notifications and state capture synchronously. Later queued writes wait for the active operation. Successful logical writes include zero-byte boundaries.Shared activation setup resolves activation-scoped observers after grain construction and assignment, before lifecycle startup. The standard grain-bound manager constructor enrolls its instance before resolution returns, and observers can register after a grain constructor has resolved that manager while journal initialization is still pending. This supports ordinary grains, application-defined base classes, injected state, and the optional
DurableGrainconvenience base. Custom implementations establish one enrollment owner in their constructor or registration factory. Explicit-JournalIdfactory-created managers retain caller-owned initialization and disposal; scoped factories which assign them a grain lifecycle explicitly enroll them before returning.Initial replay reports restored state before initialization completes. An admitted operation failure uses the terminal manager lifecycle: the original failure is recorded, optional
OnFaulted(Exception)notifications run exactly once, and owning-grain deactivation and queued/failing operation completion follow. Notification exceptions are logged and isolated; request admission vetoes reject only the unadmitted request. Idle shutdown completes normally, while cancellation during admitted preparation, finalization, or persistence remains terminal. Standalone owners recreate the manager and state instances for the same journal to recover the actual durable outcome.Adapt the observer prerequisite extracted from #10693 to the terminal recovery contract merged in #11276. The observer API uses initial replay notifications and terminal fault visibility, with operation-local staging owned by each consumer. The generic asynchronous phase hooks preserve synchronous validate/apply in exclusively owned feature state. Callbacks complete independently of further operations on the same manager.
Focused regressions cover once-only fault notification before admitted/queued callers complete, original-failure preservation when notifications fail, serialization across suspended preparation, effects-plus-completion capture, caller-wait cancellation, ordinary idle shutdown, optional default compatibility, and explicit-
JournalIdprovider-bound recovery. Composition cases verify scoped observer identity, initial replay, write phases, terminal outcomes, and fresh recovery across plain, application-base, injected-state, and convenience-base grains. Hosting, implementation registration, and explicit-ID factories verify their exact enrollment ownership and cleanup. XML docs and the generated API surface describe the lifecycle.Dependency and review boundary
#11279 has landed on
mainas0f9537dde1c10107d059fc10f1171f6f04a43f19. This PR is rebased onto that pinned main commit, which includes grain-context-constructor-owned lifecycle enrollment, shared activation setup from #11305, and the earlier Journaling/Jobs foundations.This PR targets
dotnet/orleans:mainand contains only the five observer commits across six files. Review the observer-only layer using the immutable incremental compare. Named-provider registration and Jobs migration are inherited from main. Merging remains a human decision.Microsoft Reviewers: Open in CodeFlow