Bump JasperFx from 2.49.0 to 2.54.0 - #16
Closed
dependabot[bot] wants to merge 1 commit into
Closed
Conversation
--- updated-dependencies: - dependency-name: JasperFx dependency-version: 2.54.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
Author
|
Superseded by #17. |
dependabot
Bot
deleted the
dependabot/nuget/samples/Waymark.MartenSample/JasperFx-2.54.0
branch
August 23, 2026 01:35
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.
Updated JasperFx from 2.49.0 to 2.54.0.
Release notes
Sourced from JasperFx's releases.
2.54.0
Two additive features for the Spec Driven Development track (master: JasperFx/stoat#9). Minor rather than patch because both add public surface; nothing existing is removed, renamed or obsoleted, and every existing constructor and JSON payload round-trips unchanged.
Event Modeling semantic model v2, overlay API and discovery bridge (#687, #689 — PR #691)
JasperFx.Events.EventModelingis now the one slice vocabulary every source writes into and every viewer reads from:EventModelSliceDescriptorkeeps its positional shape and gainsPattern(SlicePattern: Command / View / Automation / Translation),TriggerKind(Http / Grpc / MessageHandler / JobScheduler / Human / External),TriggerOrigin,AggregateTypes(a list — one handler may load several projected models),PublishedMessages,ExternalSystems,Hotspots,Specifications(typed:{Feature}/{Scenario}identity + resolved types, stamped by sources),Domain, plus the computed rendering contractElements(stable id, kind → canonical colour, lane) andEdges(directed, by id), andMerge(other).EventModelDescriptorgainsAggregatesand a staticMerge(name, descriptors).HandlerRelationshipDescriptor.ToSliceDescriptor()folds the older handler-relationship vocabulary into a slice.EventModelDefinition/EventModelBuilder/EventModelSliceBuildername, group (InDomain), annotate (TriggeredBy(label)) and link (LinksToSpecification) — roles are derived by the sources that can see them. The role-declaring methods live behind one documented escape hatch,ForFlowNotOwnedHere(...).EventModelDefinitionSource,services.AddEventModel<T>()/AddEventModel(type | instance | name, lambda)/AddEventModelsFromAssembly/AddEventModelSource, andEventModelDiscovery.DiscoverAsync/AssembleAsync.IEventModelDefinitionSourcefinally has implementations.HotspotDescriptor.PendingSpecification(specIdentity)— a pending specification renders as a hotspot on the slice it binds to.ProjectionScenarioexposes its plan and observes each step (#688 — PR #692)ProjectionScenario<TOperations, TQuerySession>gainsPlannedSteps(number, kind, description — readable beforeExecuteAsync) and anObserver(IProjectionScenarioObserver:StepStarted/StepSucceeded/StepFailed/StepSkipped), numbered as the exception report numbers them. Marten, Polecat and Fisher subclasses need no change.2.53.0
One fix and one documentation change. Minor rather than patch because the fix adds a member to a public interface — additive, with a default, so nothing has to change to keep compiling.
IProjectionStorage.IsThreadSafe(#683, #685)AggregationRunnerapplies every slice in a range through a fixed 10-wide block, and every one of them gets the sameIProjectionStorageinstance. That is what the products' own document storage is built for. It is not what an EF Core storage can take: it wraps oneDbContextper tenant/batch, and aDbContextis not thread-safe. A multi-stream projection with custom grouping fans one event out into many slices, so up to ten concurrently callEntry()/FindAsyncand mutate the same change tracker — surfacing asInvalidOperationExceptionout ofDictionary.TryInsertandNullReferenceExceptionout ofChangeDetector.DetectChanges(JasperFx/marten#5266).A storage can now say it cannot take that:
and the runner applies its slices one at a time. Resolved per tenant group, so a store may answer differently per tenant.
Defaults to
true, so no existing storage changes. The declaration is on the storage rather than onAsyncOptionsbecause the storage is the thing that is or is not safe and it already knows — a parallelism knob would work, but it would make correctness a configuration problem a user has to know they have.Entry()runs change detection over them, which is exactly the reportedChangeDetectorfailure. The fan-out itself has to stop, and nothing reachable from inside the storage can stop it.Both routes run the same handler and collect into the same exception list, so
MarkSliceAction, the single-vs-aggregate throw andApplyPendingCacheUpdatesare unchanged. The exception collector is now aConcurrentQueue— it had one unguarded writer already, and the serial route adds a second.Adopters: Marten JasperFx/marten#5266, Polecat JasperFx/polecat#489, Fisher JasperFx/fisher#108 — each returns
falsefrom its EF Core projection storage.One trap worth knowing if you write tests around this: NSubstitute proxies a default interface member rather than inheriting it, so
Substitute.For<IProjectionStorage<,>>().IsThreadSafeisfalseand silently takes the serial route. Harmless, since serial is always correct, but a substitute cannot exercise the concurrent route and cannot be trusted to report what a real storage would.The projection base classes now say they are not equivalent to yours (#649, #686)
Documentation only, no behavior change.
JasperFxSingleStreamProjectionBaseandJasperFxEventProjectionBaseare the shared implementations behind each store's ownSingleStreamProjection<TDoc,TId>/EventProjection— and deriving from them directly is not the same as deriving from the store's subclass. Nothing about it fails at compile time.As of Marten 9.23,
Marten.Events.Aggregation.SingleStreamProjection<TDoc,TId>adds two behaviors the base omits:BuildSlicerreturns aTenantedEventSlicerwithForceSingleTenancyfrom the store'sTenancyStyle— the fix for JasperFx/wolverine#2053ConfigureAggregateMappingsetsUseVersionFromMatchingStream = true, which changes how an aggregate's version metadata is persistedTake the base instead and you get a projection that builds, runs, and slices or versions differently. Polecat's subclass is an empty class body, so the divergence is Marten-shaped today — which is what makes it a trap: checking one store tells you nothing.
The XML docs now say this on the types themselves, and record the two routes that do work for a projection meant to compile against several stores: a per-flavour alias bound to each store's own subclass, or — where the document owns its stream — a self-aggregating document registered with
Snapshot<T>(), which sidesteps it entirely because the store then constructs its own subclass.This is the cheap half of #649. Closing the gap properly — hoisting the behavior into the base, or a seam each store fills in — is still open.
Full Changelog: JasperFx/jasperfx@V2.52.1...V2.53.0
2.52.1
A single fix. Patch release — no API additions, no behavior change for anything that was not already broken.
ShardState.Modenow reports a rebuild (#681, #682)ShardMode.rebuildinghad no writer anywhere in the tree. EveryShardStateaSubscriptionAgentpublished went out with the property's default ofcontinuous— including the ones published during a replay — so a subscriber watchingShardStateTrackercould not tell a projection catching up under a rebuild from one running normally. That is the only distinction the enum exists to draw.The agent already knew which it was; it just knew it on a different enum (
ShardExecutionMode) that was never copied onto what it published. So this is propagation, not new state.What you can now key on. An
IObserver<ShardState>seesMode == ShardMode.rebuildingfor every state a shard publishes while replaying — the start, per-batch progress, and a failure — andShardMode.continuousotherwise. That is enough to tell an operator "this projection is rebuilding, so the sequence you are watching is catch-up progress toward the rebuild's ceiling, not lag".ShardExecutionMode.CatchUpdeliberately maps tocontinuous. A shard behind the high water mark under normal operation is stillcontinuous: the number being watched is lag either way, and only a rebuild changes what it means.A finished replay drops back to
continuousbefore its teardown, so theStoppedstate disposal publishes does not still claim to be rebuilding — otherwise a consumer tracking the last state it saw would latch on "rebuilding" permanently, from a rebuild that ended cleanly.ShardModeis now documented, which it was not, because an enum with no writer had no stated meaning. Note in particular thatnonemeans "no mode was stored" — it is the default for a persisted progression row, not a running state.Upgrading
Nothing to do. Marten, Polecat and Fisher all use JasperFx's
SubscriptionAgentandShardStateTrackerdirectly — none of them implementsISubscriptionAgent— so all three pick this up on the package bump with no store-side change and no store release to wait for.One thing this does not change: Marten's persisted
modecolumn has no writer either, so aShardStatehydrated from the progression table still reportsnone. That is a separate path from the live tracker and out of scope here.Full Changelog: JasperFx/jasperfx@V2.52.0...V2.52.1
2.52
What's Changed
Full Changelog: JasperFx/jasperfx@V2.51.0...v2.52
2.51.0
Three changes to the store-agnostic contracts, all additive. No store breaks on this bump.
IDocumentSessionOperations.PendingStreams(#673, #675)A consumer holding the shared document session contract can now read the
StreamActions a session has queued but not yet committed:All three stores already surfaced the same
JasperFx.Events.StreamActioncollection under three different names — Marten'sPendingChanges.Streams(), Polecat'sPendingChanges.Streams, Fisher'sEvents.PendingStreams— so this closes a naming gap, not a capability gap. It sits on the committable tier for the same reasonEventsdoes: a stream action can only be pending in a session that can append, andIDocumentWriteOperations(the tier a projection'sRaiseSideEffectsreceives) cannot.The member carries a throwing default rather than an empty one. An empty list is indistinguishable from a session with nothing pending, so a silent default would let a consumer's derived work be discarded with a clean build and green tests.
New opt-in
PendingStreamActionsComplianceholds stores to the behavior.IAggregateWriteCache— a shared second-level snapshot cache forFetchForWriting(#674, #676)The aggregate snapshot cache built and measured for Marten is now a shared contract in
JasperFx.Events.Fetching, so Marten, Polecat and Fisher get one implementation of it rather than three.IAggregateWriteCache,AggregateCacheKey,NulloAggregateWriteCacheRecentlyUsedAggregateWriteCache— the default, bounded and node-localAggregateWriteCacheOptions— opt-in per aggregate type, off by defaultEventRegistry.CacheAggregatesForWriting<T>()— inherited by every store's event optionsThe cached snapshot is a baseline only: the stream version and every event after the cached version are still read from the database on every call, and the optimistic concurrency assertion on append is untouched. A stale entry costs a larger delta query — never a wrong aggregate, never a suppressed concurrency failure. What it removes is the snapshot load, which on the measured workload was 4.5–4.9 ms of a 13.2 ms round.
The default implementation is backed by
JasperFx.Core's existingRecentlyUsedCache, so this adds no new package dependency — a deliberate reversal of the prototype'sMicrosoft.Extensions.Caching.Memoryreference, which would have pushed that onto every store.New opt-in
AggregateWriteCacheComplianceasserts that turning caching on is unobservable except in latency, including when the cached baseline is stale, ahead of the stream, or evicted.Compliance suite fixes (#672, #677)
DocumentComplianceConfiggains a nullableStreamIdentity, so a document compliance suite can declare the stream identity style it needs instead of leaving each fixture to guess.DocumentSessionEventsComplianceappends by stream key and had no way to say so, which failed three of its five facts on every store defaulting to Guid identity — a correct store failing an undocumented precondition, which is a suite bug by definition. Additive: null means "leave the store on its own default", so no existing fixture changes.BinaryEventAttributeis no longersealed. A store that shipped its own before this one was promoted cannot delete it and could not derive from a sealed one, leaving it checking two attribute types indefinitely. Unsealing lets it subclass instead and collapse back to a single lookup, since attribute lookup matches by assignability. Stores without a pre-existing attribute should keep using the promoted one directly.Downstream
Adoption is tracked per store: Marten JasperFx/marten#5248, #5249, #5250, #5251 · Polecat JasperFx/polecat#477, #478, #479 · Fisher JasperFx/fisher#96, #97, #98.
Full Changelog: JasperFx/jasperfx@V2.49.0...V2.51.0
2.50
What's Changed
New Contributors
Full Changelog: JasperFx/jasperfx@V2.49.0...v2.50
Commits viewable in compare view.
Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting
@dependabot rebase.Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
@dependabot rebasewill rebase this PR@dependabot recreatewill recreate this PR, overwriting any edits that have been made to it@dependabot show <dependency name> ignore conditionswill show all of the ignore conditions of the specified dependency@dependabot ignore this major versionwill close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this minor versionwill close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this dependencywill close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)