Passive projection
A passive projection is a projection that is not actively materialized to a persistent store but can be queried on-demand for in-memory lookups. This is useful for scenarios where you need to construct read models from events without the overhead of maintaining persistent state.
Defining a passive projection
Section titled “Defining a passive projection”Use the .Passive() method to mark a projection as passive:
using Cratis.Chronicle.Projections;
public class UserSummaryProjection : IProjectionFor<UserSummary>{ public void Define(IProjectionBuilderFor<UserSummary> builder) => builder .Passive() .AutoMap() .From<UserCreated>() .From<UserUpdated>();}This projection:
- Will not be actively maintained in persistent storage
- Can be queried on-demand using the
IProjectionsservice - Reconstructs the read model from events when requested
Using passive projections
Section titled “Using passive projections”Passive projections are accessed through the event store’s ReadModels using the GetInstanceById method:
public class UserService{ private readonly IEventStore _eventStore;
public UserService(IEventStore eventStore) { _eventStore = eventStore; }
public async Task<UserSummary?> GetUserSummaryAsync(string userId) { return await _eventStore.ReadModels.GetInstanceById<UserSummary>(userId); }}Read model definition
Section titled “Read model definition”The read model is defined the same way as for regular projections:
public record UserSummary( string Name, string Email, int LoginCount, DateTimeOffset LastLoginAt);Event definitions
Section titled “Event definitions”Events should match the read model structure or use explicit mapping:
[EventType]public record UserCreated(string Name, string Email);
[EventType]public record UserUpdated(string Name, string Email);
[EventType]public record UserLoggedIn(DateTimeOffset LoginTime);How it works
Section titled “How it works”When you call GetInstanceById on a passive projection:
- Chronicle retrieves all relevant events for the specified event source ID
- The projection logic is applied to reconstruct the read model in memory
- The resulting read model is returned without being persisted
- Each call reconstructs the model from scratch, ensuring up-to-date data
When to use passive projections
Section titled “When to use passive projections”Passive projections are ideal for:
- Infrequent queries: When read models are accessed rarely or sporadically
- Real-time data: When you always need the most current state without caching concerns
- Memory-sensitive scenarios: When you want to avoid storing projection state
- Temporary calculations: For read models that are computed and discarded
- Testing and debugging: When you need to inspect event-driven state without persistence
Performance considerations
Section titled “Performance considerations”- Passive projections have higher latency since they reconstruct on each request
- They consume more CPU but less storage compared to active projections
- Consider caching strategies if the same passive projection is accessed frequently
- Use for read models with simple event processing logic to minimize reconstruction time