Skip to content

JasperFx 2.59.0

Choose a tag to compare

@jeremydmiller jeremydmiller released this 31 Aug 18:08
· 167 commits to main since this release

Closes the tenancy-slicing gap opened by 2.58.0, and adds two opt-in compliance suites.

Nothing here changes behavior for a store that does nothing. The fix ships inert — it activates only when a store adopts a new one-line seam — and both new suites are opt-in, so neither runs until a store enrolls it.

Changes

  • #726 — JasperFxSingleStreamProjectionBase now resolves ForceSingleTenancy itself (#723), plus SingleTenantedEventSlicingCompliance (#724) and CompositeProjectionCompliance (#725).

#723 — the tenancy seam

2.58.0 made ForceSingleTenancy take effect on the async daemon for the first time. Only Marten ever set it, by overriding BuildSlicer; Polecat's and Fisher's SingleStreamProjection<TDoc,TId> are empty class bodies. So 2.58.0 fixed wolverine#2053 / marten#4085 on one store out of three and left the other two carrying a live async-projection correctness bug.

The base now resolves it from a new IEventTenancySource on the session — the only thing BuildSlicer is handed. A session that does not implement it yields false, exactly the previous behavior, so upgrading changes nothing until a store opts in:

public TenancyStyle EventTenancyStyle => Options.Events.TenancyStyle;

The member is EventTenancyStyle rather than TenancyStyle on purpose: all three stores already declare a TenancyStyle somewhere in their options graph (Marten on EventGraph, Polecat and Fisher on EventStoreOptions), so the shorter name would bind implicitly on some and not others — silently correct in one store and silently absent in the next, which is the failure mode being ended.

Adopting this is what closes polecat#526 and fisher#139. Once adopted, Marten's own BuildSlicer override is redundant.

New compliance suites, both opt-in

SingleTenantedEventSlicingCompliance (#724) — on a single-tenanted store, events whose tenant_id values disagree must still fold into one aggregate. Drives the async daemon, since that is the only path the bug ever reached. It guards its own precondition: if a store normalizes the stamped tenant ids away on write, the fact skips with a message rather than passing vacuously.

CompositeProjectionCompliance (#725) — composite staging, one-shard identity, and member teardown on rebuild. Needs the new IComplianceStoreRegistrar.AddCompositeProjection seam, because a composite cannot be constructed by a suite: every product keeps its subclass's constructor internal. Implementations are a forward plus a small adapter, roughly three lines. Its rebuild fact is the load-bearing one, and members are additive so a store that replayed over surviving rows instead of tearing them down reads back exactly doubled.

Both are documented in the package README, along with the new seam.