Skip to content

JasperFx 2.81.0

Choose a tag to compare

@jeremydmiller jeremydmiller released this 05 Oct 23:37

⚠️ 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 ProgressionProgressOutOfOrderException and 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 StopAndDrainTimeout is 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, raise StopAndDrainTimeout.
  • Rebuilds, replays and composite-projection stages that call ProcessRangeAsync directly 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. SaveChangesAsync is 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(...) with ConfigureDocuments, ConfigureEvents and ConfigureProjections.
  • 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) and InChapter (#957).
  • A type declared by name and the real type are reconciled into one element (#958). A fluent definition names itself as the Origin on 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

  • SourceWriter output: no blank line before }, else, catch or the end of the file. END is only recognised as a whole directive, and there is now a way to emit a backtick (#956).
  • ShardName construction is ~3–8x faster and TryParse ~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 BlockIdleWakeupTests inline-execution assertion (#973), and one in the BlueGreen gate test harness (#983).
  • The docs PR workflow now targets main and actually builds the docs (#794).

Full Changelog: V2.80.1...V2.81.0