Skip to content

IEventStream<T> compound-handler append is silently dropped without AutoApplyTransactions (inconsistent with [AggregateHandler]/IMartenOp after GH-3025) #3032

Closed

Description

@jeremydmiller

Found while building the #3021 Phase-1 tenant-partitioned aggregate matrix.

Summary

A handler that obtains an IEventStream<T> via the compound-handler Load/LoadAsync convention (FetchForWriting<T>) and appends to it gets no Marten transaction support — SaveChangesAsync is never generated — unless opts.Policies.AutoApplyTransactions() is enabled. The append is then silently dropped: no events persisted, no exception.

This is inconsistent with the other handler-side Marten effects, which do self-persist without AutoApplyTransactions:

Repro

public static class AppendViaStreamHandler
{
    public static Task<IEventStream<Thing>> LoadAsync(Cmd c, IDocumentSession s, CancellationToken ct)
        => s.Events.FetchForWriting<Thing>(c.Id, ct);

    // append-only; no [AggregateHandler], no IMartenOp return
    public static void Handle(Cmd c, IEventStream<Thing> stream)
        => stream.AppendOne(new ThingHappened(...));
}

Host without AutoApplyTransactions() → after invoking Cmd, FetchStreamAsync(id) shows the append never landed.

Observations:

  • Adding IDocumentSession session to the Handle signature (the // Works variant in Bug_225_compound_handlers_and_marten_event_streams) does not fix it on its own — that variant's comment is only accurate with AutoApplyTransactions on.
  • Bug_225.should_apply_transaction passes precisely because it enables AutoApplyTransactions().
  • Not partitioning-specific — reproduces on a plain Conjoined/non-partitioned store too; the partitioned matrix just surfaced it.

Question / ask

Post-#3025 the principle seems to be "handler-side Marten effects persist without requiring AutoApplyTransactions." The FetchForWriting → IEventStream<T> append path is the remaining hole. Options:

  1. Detect a handler that loads/appends to an IEventStream<T> (compound-handler Load returning IEventStream<T>, or an IEventStream<T> parameter) and apply the same idempotent Marten transaction support MartenOpPolicy/the aggregate workflow already apply — making it persist without AutoApplyTransactions.
  2. Or, if AutoApplyTransactions is intended to be required for this shape, surface it (startup/analyzer diagnostic) instead of silently dropping the append.

Context

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions