Skip to content

Reducers

Reducers provide a way to build read models by reducing a sequence of events into a single state. Unlike projections, which focus on transforming individual events into read models, reducers process collections of events together to compute derived state.

A reducer is a specialized observer that:

  • Processes multiple events together - Events are grouped by event source and passed to the reducer as a collection
  • Computes derived state - The reducer method receives the current state and returns the new state after processing the events
  • Maintains temporal consistency - All events for a given event source are processed in order
  • Supports snapshots - The computed state can be retrieved at any point in the event stream

Reducers are ideal when you need to:

  • Aggregate data across multiple events - Calculate sums, averages, or other metrics from a series of events
  • Build temporal models - Track how state changes over time
  • Implement complex business logic - Process events together to derive insights that span multiple events
  • Create snapshots - Capture the state of a read model at specific points in time
using Cratis.Chronicle.Events;
using Cratis.Chronicle.Reducers;
[EventType]
public record ReducersIndexDepositMade(decimal Amount);
[EventType]
public record ReducersIndexWithdrawalMade(decimal Amount);
public record ReducersIndexAccountBalance(decimal Balance, DateTimeOffset LastUpdated);
public class ReducersIndexAccountBalanceReducer : IReducerFor<ReducersIndexAccountBalance>
{
public ReducersIndexAccountBalance Deposited(ReducersIndexDepositMade @event, ReducersIndexAccountBalance? current, EventContext context)
{
var currentBalance = current?.Balance ?? 0m;
return new ReducersIndexAccountBalance(currentBalance + @event.Amount, context.Occurred);
}
public ReducersIndexAccountBalance WithdrawalMade(ReducersIndexWithdrawalMade @event, ReducersIndexAccountBalance? current, EventContext context)
{
var currentBalance = current?.Balance ?? 0m;
return new ReducersIndexAccountBalance(currentBalance - @event.Amount, context.Occurred);
}
}

Once you’ve defined a reducer, you can retrieve and observe the resulting read models using the IReadModels API: