Per-tenant-partitioned-events Phase 1 (cont.): required-write isolation, optimistic version, cascading tenant inheritance (#3021)#3026
Merged
Conversation
…on, optimistic version, cascading tenant inheritance (#3021) Extends the single-store partitioned-events aggregate matrix with three more tenant-scoped scenarios against a Conjoined + Quick + UseTenantPartitionedEvents store: - [WriteAggregate(Required=true, OnMissing=ThrowException)]: an aggregate present in tenant1 but routed to tenant2 raises RequiredDataMissingException (partition isolation) rather than starting a tenant2 stream. - Optimistic version check ([AggregateHandler(VersionSource=...)]) is scoped to the tenant's partition: correct version appends in the routed tenant only; a stale version raises ConcurrencyException; the sibling tenant's own version is unaffected. - A message cascaded from an aggregate handler inherits the handler's tenant (outbox session is tenant-scoped). Finding (filed as #3025): MartenOps.StartStream returned from a handler is silently dropped under UseTenantPartitionedEvents (0 events persisted), while a direct session.Events.StartStream persists. Earlier tests masked this because the aggregate handlers start-if-missing; these version/required scenarios are the first that need a genuinely pre-existing stream, so the seed now uses a direct tenant session. Full AggregateHandlerWorkflow folder green (80). Remaining Phase-1 clusters (natural-key, MartenOps document tenant overloads, event-as-message, ancillary stores, HTTP) and Phases 2-3 (distribution, sharded) remain on #3021. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Closed
17 tasks
This was referenced Jun 8, 2026
Merged
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Advances #3021. Test-only (no shippable change). Builds on the merged Phase-1 slice (#3022) with three more single-store, tenant-scoped aggregate-handler scenarios against a
Conjoined + Quick + UseTenantPartitionedEventsstore:[WriteAggregate(Required=true, OnMissing=ThrowException)]isolation — aggregate present in tenant1 but routed to tenant2 →RequiredDataMissingException(not a silently-started tenant2 stream).[AggregateHandler(VersionSource=...)]) scoped to the tenant partition — correct version appends in the routed tenant only; stale version →ConcurrencyException; sibling tenant's version unaffected.Bug found + filed: #3025
While building these I found that
MartenOps.StartStreamreturned from a handler is silently dropped underUseTenantPartitionedEvents(0 events persisted), whereas a directsession.Events.StartStreampersists. The earlier tests masked this because aggregate handlers start-if-missing — these version/required scenarios are the first that need a genuinely pre-existing stream. The seed therefore uses a direct tenant session, with a comment pointing at #3025.Verification
Full
MartenTests/AggregateHandlerWorkflowfolder green (80, +3).Still on #3021 (deferred)
Natural-key aggregate,
MartenOpsdocument tenant overloads, event-as-message, ancillary stores, the HTTP[Aggregate]/[WriteAggregate]/[ReadAggregate]cluster (needs an Alba host), and all of Phase 2 (multi-node projection/subscription distribution) + Phase 3 (sharded DBs). The single-PR goal hit two practical limits: the #3025 StartStream bug (worked around), and the HTTP/multi-node clusters needing separate harnesses — so those are tracked rather than forced in.🤖 Generated with Claude Code