Skip to content

Backport: feat(persistence): completion callbacks via Defer#7957

Merged
Aaronontheweb merged 1 commit into
akkadotnet:v1.5from
Aaronontheweb:backport/v1.5-persistence-completion-callbacks
Dec 2, 2025
Merged

Backport: feat(persistence): completion callbacks via Defer#7957
Aaronontheweb merged 1 commit into
akkadotnet:v1.5from
Aaronontheweb:backport/v1.5-persistence-completion-callbacks

Conversation

@Aaronontheweb
Copy link
Copy Markdown
Member

Backport of #7954 to v1.5 branch.

Original PR

#7954 - feat(persistence): completion callbacks via Defer - simplified alternative to #7937

Summary

Adds completion callback support for persistence operations using the Defer mechanism.

…ative to akkadotnet#7937 (akkadotnet#7954)

* feat(persistence): add completion callbacks and async handler support

Add completion callback overloads for PersistAll and PersistAllAsync that
invoke a callback after all events have been persisted and their handlers
executed. Also add async handler support (Func<TEvent, Task>) to all
persist methods.

Key changes:
- Add IPendingHandlerInvocation, ISyncHandlerInvocation, IAsyncHandlerInvocation,
  and IStashingInvocation interfaces for type-safe handler invocation
- Add StashingHandlerInvocation, StashingAsyncHandlerInvocation,
  AsyncHandlerInvocation, and AsyncAsyncHandlerInvocation classes
- Add Persist<TEvent>(TEvent, Func<TEvent, Task>) async handler overload
- Add PersistAsync<TEvent>(TEvent, Func<TEvent, Task>) async handler overload
- Add PersistAll overloads with completion callbacks (sync and async)
- Add PersistAllAsync overloads with completion callbacks (sync and async)
- Add DeferAsync<TEvent>(TEvent, Func<TEvent, Task>) async handler overload
- Add internal stashing Defer methods for completion callback support
- Update PeekApplyHandler to handle async handlers via RunTask
- Update PersistingEvents to use IStashingInvocation marker interface

Stashing semantics are preserved: PersistAll completion callbacks use
internal stashing Defer (increments _pendingStashingPersistInvocations),
while PersistAllAsync uses non-stashing DeferAsync.

* chore: update API approval for persistence completion callbacks

Update verified API file to reflect:
- New public methods: Persist/PersistAsync/PersistAll/PersistAllAsync async
  handler overloads and completion callback overloads
- New public method: DeferAsync with async handler
- Internal invocation classes: AsyncHandlerInvocation, StashingHandlerInvocation,
  and IPendingHandlerInvocation are now internal (implementation detail)

* chore: update .NET Framework API approval for persistence completion callbacks

* fixed API approvals

* test(persistence): add empty events tests and convert to async test methods

- Convert all tests to use async/await with ExpectMsgAsync instead of
  sync-over-async ExpectMsg calls
- Add tests for PersistAll/PersistAllAsync with empty events to verify
  completion callbacks are invoked immediately for all overloads:
  - PersistAll with sync completion callback (existing)
  - PersistAll with async completion callback (new)
  - PersistAllAsync with sync completion callback (new)
  - PersistAllAsync with async completion callback (new)
- Update EmptyEventsWithCompletionActor to support all four scenarios

* fix(persistence): use Defer for empty events completion callbacks to maintain ordering

When PersistAll/PersistAllAsync is called with empty events, the completion
callback must still be queued through Defer/DeferAsync to maintain the
in-order execution guarantee. Previously, the callback was invoked immediately
which could cause out-of-order execution if there were pending invocations
from prior Persist/PersistAll calls.

Changes:
- Replace immediate invocation with Defer/DeferAsync for all 8 overloads
  that have completion callbacks when events collection is null or empty
- Add SequentialPersistOrderingActor test actor for ordering verification
- Add test: Persist followed by empty PersistAll maintains execution order
- Add test: Sequential PersistAll with empty in middle maintains order
@Aaronontheweb Aaronontheweb added this to the 1.5.57 milestone Dec 2, 2025
@Aaronontheweb Aaronontheweb enabled auto-merge (squash) December 2, 2025 22:54
@Aaronontheweb Aaronontheweb merged commit 43838bf into akkadotnet:v1.5 Dec 2, 2025
11 checks passed
@Aaronontheweb Aaronontheweb deleted the backport/v1.5-persistence-completion-callbacks branch December 3, 2025 01:13
This was referenced Dec 3, 2025
This was referenced May 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant