Skip to content

Fix #4730 — bump JasperFx to 2.9.10 (aggregate-cache double-apply) + regression test#4731

Merged
jeremydmiller merged 1 commit into
masterfrom
fix-4730-consume-jasperfx-2.9.10
Jun 12, 2026
Merged

Fix #4730 — bump JasperFx to 2.9.10 (aggregate-cache double-apply) + regression test#4731
jeremydmiller merged 1 commit into
masterfrom
fix-4730-consume-jasperfx-2.9.10

Conversation

@jeremydmiller

Copy link
Copy Markdown
Member

Closes #4730. Consumes the upstream fix (jasperfx#444, shipped in JasperFx 2.9.10).

The bug

An async aggregate projection double-applied a correctly-ordered "control" stream's event when an unrelated stream in the same page threw during apply (an out-of-order Update-before-Create). Reproduced cleanly: the control stream's value came out expected. Worked in 9.6, broke in 9.7.

Root cause (fixed upstream)

The in-memory aggregate cache was turned on by default in JasperFx 2.9.0 and isn't transactional — AggregationRunner wrote the mutated aggregate to the cache during batch build, before commit. When the poison event triggered buildBatchWithSkipping to skip-and-rebuild, the rebuild read the already-mutated control aggregate back from the cache and applied its events again.

What 2.9.10 changes

This PR

  • Bumps the four JasperFx.* packages 2.9.9 → 2.9.10 in Directory.Packages.props.
  • Adds Bug_4730_double_apply_with_out_of_order_stream, a theory over CacheLimitPerTenant 0 and 1000 so it permanently guards both halves of the fix (default-off and populate-on-commit): the control stream's Update must be applied exactly once even though a sibling stream throws.

Verification

  • Bug_4730 — 2/2 green against the published 2.9.10 (cache off and cache on). The same test fails on 2.9.9.
  • Composite + rebuild daemon slice (42 tests incl. Bug_4730, Bug_4428) — green.

🤖 Generated with Claude Code

…regression test

2.9.10 carries #444: the async aggregate cache is OFF by default again
(CacheLimitPerTenant 1000 → 0) and, when enabled, only populates after the owning
batch commits. Previously the cache was written during batch build before commit,
so a failed/retried batch (e.g. an out-of-order Update-before-Create stream throwing
ApplyEventException → skip-and-rebuild) re-applied events on top of the already-
mutated cached aggregate, double-applying to unrelated, correctly-ordered streams in
the same page.

Bug_4730 is a theory over CacheLimitPerTenant 0 (default) and 1000 (cache on), so it
guards both halves of the fix: the control stream's Update must be applied exactly
once even though a sibling stream throws. Verified green against 2.9.10 (both cases).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jeremydmiller jeremydmiller merged commit 7fe8498 into master Jun 12, 2026
8 checks passed
@jeremydmiller jeremydmiller deleted the fix-4730-consume-jasperfx-2.9.10 branch June 12, 2026 14:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Async projection appears to apply update event twice when mixed with out-of-order stream scenario

1 participant