Skip to content

0.9.1

Choose a tag to compare

@jeremydmiller jeremydmiller released this 18 Aug 00:24
· 3 commits to main since this release
cfaad93

A single fix — #102, found from one intermittent CI failure while 0.9.0 was being released.

Non-stale waits on the shards the store registers

WaitForNonStaleProjectionDataAsync — and QueryForNonStaleData behind it — decided it was done from the rows in fi_event_progression rather than from the shards the store registers. A shard that has not started has no row and therefore no sequence to be behind, so it was invisible: with two async projections the wait returned the moment the first one reached the head.

What that costs is the whole point of the call. An application asking for non-stale data was told its data was current while a projection had never run, and read empty documents that look like real answers.

The same rule was broken the other way round, which fixing it surfaced: with events present and no progression rows at all, a store with no async projections waited out its timeout on every call.

Registered shards are now the authority in both directions:

registered shard, no row stale
registered shard, behind stale (unchanged)
no async projections registered returns immediately
row for a shard nothing registers ignored — an orphan from a de-registered projection never advances again

⚠️ Behaviour change

A wait with a registered async projection and no daemon running now waits out its timeout and throws TimeoutException, where it used to return early. That is the honest answer — nothing is going to advance that shard — but it will surface anywhere a test waits for non-stale data without starting a daemon. The message now names the shards that have recorded nothing at all, so "never started" reads differently from "still catching up".

Why it took an intermittent to find

It presented once, as rebuild_and_catch_up_compliance.rebuilding_one_projection_leaves_another_alone on a loaded two-core CI runner — green on the other target framework in the same run and 25/25 locally in isolation. The window is the gap between one shard's first commit and the next shard's.

The regression test is seeded rather than raced, and it needs two registered shards: with no rows at all the old rule waited too, so a store where nothing has run cannot tell the two rules apart. Mutation-checked — reverting to the row-derived rule fails it and the two "returns immediately" facts.

Compatibility

No API changes. Requires JasperFx 2.51.0; Weasel stays at 9.24.0. Everything in 0.9.0 — the aggregate write cache, PendingStreams, and the 2.51.0 bump — is unchanged.