Skip to content

Persist single IMartenOp side-effect returns; bump 6.4.4 (GH-3025)#3029

Merged
jeremydmiller merged 1 commit into
mainfrom
fix-3025-startstream-partitioned
Jun 4, 2026
Merged

Persist single IMartenOp side-effect returns; bump 6.4.4 (GH-3025)#3029
jeremydmiller merged 1 commit into
mainfrom
fix-3025-startstream-partitioned

Conversation

@jeremydmiller

Copy link
Copy Markdown
Member

Closes #3025.

Problem

A handler that returns a single IMartenOp — e.g. MartenOps.StartStream<T>(...) or MartenOps.Store(doc) — silently dropped its work unless the app happened to enable Policies.AutoApplyTransactions(). No events/documents persisted, no exception. A direct session.Events.StartStream(...) persisted fine.

Surfaced via per-tenant event partitioning (Events.UseTenantPartitionedEvents), but not partitioning-specific — it reproduces on any plain Marten host without AutoApplyTransactions.

Root cause

A single IMartenOp return is an ISideEffect, so Wolverine generates the Execute() call onto the document session — but MartenOpPolicy only applied Marten transaction support (the SaveChangesAsync postprocessor via MartenPersistenceFrameProvider.ApplyTransactionSupport) for IEnumerable<IMartenOp> returns. So a single op was executed onto the session and then never committed.

Fix

MartenOpPolicy.Apply now also detects single IMartenOp returns and applies transaction support for them. ApplyTransactionSupport is idempotent (guards on CreateDocumentSessionFrame + DocumentSessionSaveChanges), so this composes cleanly with aggregate handlers and with AutoApplyTransactions. The single op's Execute() stays with the ISideEffect machinery — no ForEachMartenOpFrame is added for singles, so there's no double-execute.

Tests

New single_marten_op_side_effect_persists (MartenTests) — a host without AutoApplyTransactions invokes a handler returning a single MartenOps.StartStream and a single MartenOps.Store; both assert the data persisted. Both fail without the fix (stream count 0 / document null), pass with it.

  • Full wolverine.slnx Release build: 0 warnings, 0 errors.
  • Full MartenTests suite: 477 passing.

Carries the version bump to 6.4.4. Companion fix #3027 (PR #3028) has no bump; both should land before the next NuGet so 6.4.4 ships with both fixes.

🤖 Generated with Claude Code

….4.4 (GH-3025)

A handler returning a single IMartenOp (e.g. MartenOps.StartStream / MartenOps.Store) is an
ISideEffect — Wolverine generates the Execute() call onto the document session — but MartenOpPolicy
only applied Marten transaction support (the SaveChangesAsync postprocessor) for IEnumerable<IMartenOp>
returns. So a single op was executed onto the session and then silently dropped unless the app
happened to enable AutoApplyTransactions.

MartenOpPolicy now applies transaction support for single IMartenOp returns too. ApplyTransactionSupport
is idempotent (guards CreateDocumentSessionFrame + DocumentSessionSaveChanges), so this composes with
aggregate handlers and AutoApplyTransactions. The single op's Execute stays with the ISideEffect
machinery (no foreach frame, so no double-execute).

(Surfaced via per-tenant event partitioning, but not partitioning-specific: a test host without
AutoApplyTransactions dropped a handler's MartenOps.StartStream entirely; direct
session.Events.StartStream persisted. Regression test covers single StartStream + single Store with
no AutoApplyTransactions — both fail without the fix.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jeremydmiller jeremydmiller merged commit 75e36e0 into main Jun 4, 2026
24 checks passed
This was referenced Jun 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant