Fix racy CurrentEventsByTag_should_find_existing_events test - #76
Open
Aaronontheweb wants to merge 2 commits into
Open
Fix racy CurrentEventsByTag_should_find_existing_events test#76Aaronontheweb wants to merge 2 commits into
Aaronontheweb wants to merge 2 commits into
Conversation
Override the base TCK test to account for EventStore's eventually consistent projections. The base test uses backpressure (Request 2, ExpectNoMsg, Request 2) to page through a tagged stream, but the EventStore projection may complete before all events are indexed, causing OnComplete to race with ExpectNoMsg. The override adds a 300ms delay for projection catch-up and requests all events at once, consistent with the existing override pattern used by ReadJournal_query_CurrentEventsByTag_should_see_all_150_events.
Aaronontheweb
enabled auto-merge (squash)
March 17, 2026 17:01
Aaronontheweb
disabled auto-merge
March 17, 2026 17:01
… catch-up EventStore projections are eventually consistent. Instead of sleeping for an arbitrary duration and hoping the projection has caught up, poll the projection using AwaitConditionAsync until the expected number of events are indexed. This eliminates the race condition that caused flaky failures in CurrentEventsByTag_should_find_existing_events. Also fixes the same non-deterministic pattern in the 150-event test and the offset exclusivity test.
Aaronontheweb
added a commit
to Aaronontheweb/akka.net
that referenced
this pull request
Mar 17, 2026
Add a protected virtual extensibility point to CurrentAllEventsSpec, CurrentEventsByTagSpec, and CurrentEventsByPersistenceIdSpec that is called after events are written and before queries are executed. Backends with eventually-consistent read models (EventStore, Kafka, etc.) can override this method to wait for their read side to catch up, instead of being forced to override entire TCK test methods with Thread.Sleep hacks. Evidence: akkadotnet/Akka.Persistence.EventStore#76
2 tasks
Aaronontheweb
added a commit
to Aaronontheweb/akka.net
that referenced
this pull request
Mar 17, 2026
Replace the virtual WaitForReadSideAsync() hook with inline polling using AwaitConditionAsync. Each test now polls its respective Current* query until the expected number of events are indexed before running assertions. This is deterministic: synchronous backends pass on the first poll, eventually-consistent backends converge. Fixes the root cause of flaky TCK failures in backends like EventStore where projections are eventually consistent. Previously, these backends were forced to override entire test methods with Thread.Sleep hacks. Evidence: akkadotnet/Akka.Persistence.EventStore#76
Aaronontheweb
added a commit
to akkadotnet/akka.net
that referenced
this pull request
Mar 17, 2026
* Add WaitForReadSideAsync() hook to Persistence TCK query specs Add a protected virtual extensibility point to CurrentAllEventsSpec, CurrentEventsByTagSpec, and CurrentEventsByPersistenceIdSpec that is called after events are written and before queries are executed. Backends with eventually-consistent read models (EventStore, Kafka, etc.) can override this method to wait for their read side to catch up, instead of being forced to override entire TCK test methods with Thread.Sleep hacks. Evidence: akkadotnet/Akka.Persistence.EventStore#76 * Make TCK query specs tolerant of eventually-consistent backends Replace the virtual WaitForReadSideAsync() hook with inline polling using AwaitConditionAsync. Each test now polls its respective Current* query until the expected number of events are indexed before running assertions. This is deterministic: synchronous backends pass on the first poll, eventually-consistent backends converge. Fixes the root cause of flaky TCK failures in backends like EventStore where projections are eventually consistent. Previously, these backends were forced to override entire test methods with Thread.Sleep hacks. Evidence: akkadotnet/Akka.Persistence.EventStore#76
Aaronontheweb
added a commit
to akkadotnet/akka.net
that referenced
this pull request
Apr 24, 2026
* Add WaitForReadSideAsync() hook to Persistence TCK query specs Add a protected virtual extensibility point to CurrentAllEventsSpec, CurrentEventsByTagSpec, and CurrentEventsByPersistenceIdSpec that is called after events are written and before queries are executed. Backends with eventually-consistent read models (EventStore, Kafka, etc.) can override this method to wait for their read side to catch up, instead of being forced to override entire TCK test methods with Thread.Sleep hacks. Evidence: akkadotnet/Akka.Persistence.EventStore#76 * Make TCK query specs tolerant of eventually-consistent backends Replace the virtual WaitForReadSideAsync() hook with inline polling using AwaitConditionAsync. Each test now polls its respective Current* query until the expected number of events are indexed before running assertions. This is deterministic: synchronous backends pass on the first poll, eventually-consistent backends converge. Fixes the root cause of flaky TCK failures in backends like EventStore where projections are eventually consistent. Previously, these backends were forced to override entire test methods with Thread.Sleep hacks. Evidence: akkadotnet/Akka.Persistence.EventStore#76
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.
Summary
ReadJournal_query_CurrentEventsByTag_should_find_existing_eventsfrom the base TCKCurrentEventsByTagSpecto fix a flaky test caused by EventStore's eventually consistent projectionsRequest(2),ExpectNoMsg,Request(2)) against a projected tag stream, butOnCompleteraces withExpectNoMsgwhen the projection hasn't indexed all events yetReadJournal_query_CurrentEventsByTag_should_see_all_150_eventsRoot Cause
The base TCK test writes 6 events (3 tagged "green"), then immediately queries
CurrentEventsByTag("green", NoOffset). It requests only 2 items, expects them, then callsExpectNoMsg(500ms)before requesting more. However, EventStore projections are eventually consistent -- the projected tag stream may only contain the first 2 green events when queried, causing the stream to complete immediately andOnCompleteto arrive during theExpectNoMsgwindow (observed arriving after just 36 nanoseconds).Test plan
OnCompleteduringExpectNoMsg)