fix: filter read_events by event_type to prevent projection stalls#373
Merged
fix: filter read_events by event_type to prevent projection stalls#373
Conversation
When `read_events` is called, the LIMIT/take is applied before deserialization filtering. If the events table contains events of mixed types, non-matching events consume batch slots. When an entire batch consists of non-matching types, the projection pipeline sees zero events and stops — permanently stuck behind a block of unrelated events. All three backends (postgres, sqlite, memory) already store event_type during append. This commit adds event_type filtering at the query/scan level so non-matching events never consume batch slots: - Add `event_type` field to `EventFilter` with builder/accessor methods - In-memory backend: store event_type in GlobalLogEntry, filter before .take() - PostgreSQL backend: add WHERE event_type = $N to all SQL branches - SQLite backend: add AND event_type = ?N to all SQL branches - Projection pipeline: set event_type from E::event_type_name() in the ReadEvents effect - All backends fall back to E::event_type_name() when no explicit filter is set Closes #372
jwilger
approved these changes
Apr 15, 2026
Merged
jwilger-ai-bot
pushed a commit
that referenced
this pull request
Apr 17, 2026
## 🤖 New release * `eventcore-macros`: 0.7.0 -> 0.7.1 * `eventcore-types`: 0.7.0 -> 0.7.1 (✓ API compatible changes) * `eventcore-postgres`: 0.7.0 -> 0.7.1 (✓ API compatible changes) * `eventcore-sqlite`: 0.7.0 -> 0.7.1 (✓ API compatible changes) * `eventcore`: 0.7.0 -> 0.7.1 (✓ API compatible changes) * `eventcore-memory`: 0.7.0 -> 0.7.1 (✓ API compatible changes) * `eventcore-testing`: 0.7.0 -> 0.7.1 (✓ API compatible changes) * `eventcore-examples`: 0.7.0 -> 0.7.1 <details><summary><i><b>Changelog</b></i></summary><p> ## `eventcore-macros` <blockquote> ## [0.7.0](eventcore-macros-v0.6.0...eventcore-macros-v0.7.0) - 2026-04-13 ### Bug Fixes - improve error message consistency, context, and safety across all crates ([#352](#352)) ### Features - enhance require! macro to accept typed error values ([#335](#335)) - add required event_type_name() to Event trait for stable storage ([#344](#344)) ### Miscellaneous Tasks - adopt han plugins, blueprints, and project conventions ([#330](#330)) - consolidate workspace lints and enforce strict lint policy ([#351](#351)) ### Refactoring - expose projection config via free function API, then reduce public surface ([#357](#357)) </blockquote> ## `eventcore-types` <blockquote> ## [0.7.1](eventcore-types-v0.7.0...eventcore-types-v0.7.1) - 2026-04-15 ### Bug Fixes - filter read_events by event_type to prevent projection stalls ([#373](#373)) </blockquote> ## `eventcore-postgres` <blockquote> ## [0.7.1](eventcore-postgres-v0.7.0...eventcore-postgres-v0.7.1) - 2026-04-15 ### Bug Fixes - filter read_events by event_type to prevent projection stalls ([#373](#373)) ### Features - add load-testing/stress-testing suite ([#370](#370)) </blockquote> ## `eventcore-sqlite` <blockquote> ## [0.7.1](eventcore-sqlite-v0.7.0...eventcore-sqlite-v0.7.1) - 2026-04-15 ### Bug Fixes - filter read_events by event_type to prevent projection stalls ([#373](#373)) </blockquote> ## `eventcore` <blockquote> ## [0.7.1](eventcore-v0.7.0...eventcore-v0.7.1) - 2026-04-15 ### Bug Fixes - filter read_events by event_type to prevent projection stalls ([#373](#373)) ### Features - add load-testing/stress-testing suite ([#370](#370)) </blockquote> ## `eventcore-memory` <blockquote> ## [0.7.1](eventcore-memory-v0.7.0...eventcore-memory-v0.7.1) - 2026-04-15 ### Bug Fixes - filter read_events by event_type to prevent projection stalls ([#373](#373)) </blockquote> ## `eventcore-testing` <blockquote> ## [0.7.1](eventcore-testing-v0.7.0...eventcore-testing-v0.7.1) - 2026-04-15 ### Features - add load-testing/stress-testing suite ([#370](#370)) </blockquote> ## `eventcore-examples` <blockquote> ## [0.7.0](eventcore-examples-v0.6.0...eventcore-examples-v0.7.0) - 2026-04-13 ### Bug Fixes - improve error message consistency, context, and safety across all crates ([#352](#352)) ### Features - add required event_type_name() to Event trait for stable storage ([#344](#344)) - add TestScenario GWT testing helpers to eventcore-testing ([#346](#346)) ### Miscellaneous Tasks - consolidate workspace lints and enforce strict lint policy ([#351](#351)) ### Refactoring - replace into_inner() with into() for nutype domain types ([#334](#334)) - expose projection config via free function API, then reduce public surface ([#357](#357)) </blockquote> </p></details> --- This PR was generated with [release-plz](https://github.com/release-plz/release-plz/).
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
read_eventssilently drops events that fail deserialization via.ok(), and theLIMIT/.take()is applied before the deserialization filter. When a batch consists entirely of non-matching event types, the projection pipeline sees zero events and stops — permanently stuck.event_typeat the query/scan level so non-matching events never consume batch slots.E::event_type_name()in theEventFilter, and all backends fall back to it when no explicit filter is set.Changes
eventcore-types/src/projection.rsevent_type: Option<String>toEventFilterwith builder and accessoreventcore-memory/src/lib.rsevent_typeinGlobalLogEntry, filter before.take()eventcore-postgres/src/lib.rsWHERE event_type = $Nto all 4 SQL query brancheseventcore-sqlite/src/lib.rsAND event_type = ?Nto all 4 SQL query brancheseventcore/src/projection_pipeline.rsevent_typefromE::event_type_name()inReadEventseffecteventcore/tests/mixed_event_type_projection_test.rsCargo.lockrustls-webpki0.103.10 → 0.103.12 (security advisory fix)Test plan
read_events_returns_matching_events_when_preceded_by_other_types— seeds 5 AlphaEvents + 1 BetaEvent, callsread_events::<BetaEvent>with batch size 3, asserts 1 event returned (was 0 before fix)run_projection_processes_events_when_other_event_types_exist— fullrun_projectionintegration test with mixed event typescargo clippy,cargo fmt,cargo auditall cleanCloses #372