Repository navigation
JasperFx 2.81.0
⚠️ Behaviour change: daemon drains are bounded by StopAndDrainTimeout
StopAndDrainAsync now honours DaemonSettings.StopAndDrainTimeout (default 5 seconds) for both event subscriptions (#953) and async projection shards (#980).
- Before: the drain ignored the timeout and ran every queued range, so in practice it had no bound.
- Now: a stopping shard finishes the page in flight and skips the ranges still queued. The next owner of the shard picks those up from the stored progression. If the in-flight range is still running when the timeout expires, it is cancelled. Its batch (projection or subscription writes plus progression) rolls back, and whichever node runs the shard next processes the range again.
What this means for Marten, Polecat and Fisher users:
- Fixes a real failure. A node that loses a shard's lock no longer keeps processing its backlog while the new owner runs the shard. That overlap could end in
ProgressionProgressOutOfOrderExceptionand a Stopped shard. - Graceful shutdown is bounded. It no longer waits for the whole backlog, which could run past a Kubernetes termination grace period.
- Slow pages will see more redelivery. A page that takes longer than
StopAndDrainTimeoutis cancelled on every shutdown or rebalance and then run again. Delivery was always at-least-once, but duplicates will now happen more often for slow pages. Side effects outside the store session aren't rolled back, such as HTTP calls or sends that bypass the outbox. If your pages are slow, raiseStopAndDrainTimeout. - Rebuilds, replays and composite-projection stages that call
ProcessRangeAsyncdirectly are unaffected.
Downstream adoption: JasperFx/marten#5610, JasperFx/polecat#744, JasperFx/fisher#434.
New: JasperFx.Events.InMemory, a store for prototyping (#962)
A new package with an in-memory document and event store, meant for short-lived prototyping, before you pick Marten, Polecat or Fisher. It is not meant for production use.
- Documents (#963): promoted from the test suite.
SaveChangesAsyncis now all-or-nothing. - Events (#964):
StartStream/append,FetchForWriting/FetchLatest, live aggregation, and inline single- and multi-stream projections. It is validated against the event compliance suites. - Registration (#979):
AddInMemoryStoreForPrototyping(...)withConfigureDocuments,ConfigureEventsandConfigureProjections. - Guardrails (#965): it logs a startup warning, and refuses to start in Production with a
NotSupportedException. - Out of scope: async daemon, tag (DCB) queries, tenancy and search. Projection classes don't move between stores, but self-aggregating aggregates and store-agnostic Wolverine handlers do.
New: the event model in code (#955)
- The fluent event model declares roles by type or by name:
Command<T>(),Automation(..),View<T>(),Translation(..),Slice(name)andInChapter(#957). - A type declared by name and the real type are reconciled into one element (#958). A fluent definition names itself as the
Originon its slices (#959). - Domain (module) membership is declared through assembly or namespace policies, or with
[Domain]on handlers and endpoints (#960). - A slice-name collision now raises a hotspot instead of being silently folded (#954).
- Docs: from overlay-only to a declared model over stub types (#961).
Improvements
SourceWriteroutput: no blank line before},else,catchor the end of the file.ENDis only recognised as a whole directive, and there is now a way to emit a backtick (#956).ShardNameconstruction is ~3–8x faster andTryParse~2–4x faster, both with roughly half the allocations, which matters on stores with thousands of tenant shards (#952).- Native AOT: strong-typed aggregate identity sources work (#950, shipped in the untagged 2.80.2 package).
Fixes
- Fixed a race in the
BlockIdleWakeupTestsinline-execution assertion (#973), and one in the BlueGreen gate test harness (#983). - The docs PR workflow now targets
mainand actually builds the docs (#794).
Full Changelog: V2.80.1...V2.81.0