Skip to content

Event Sequence

By default, reducers observe the default event log. You can override this by specifying a different event sequence using either the [EventSequence] attribute or the eventSequence parameter on the [Reducer] attribute.

For a self reducer, place sequence configuration on the model itself. It has the same sequence selection and external-store routing rules as a classic reducer; a sequence attribute alone does not make it a model-bound projection.

Apply [EventSequence] directly to your reducer class to pin it to a specific event sequence:

using Cratis.Chronicle.Events;
using Cratis.Chronicle.EventSequences;
using Cratis.Chronicle.Reducers;
[EventType]
public record ReducersEventSequenceShipmentDispatched(string TrackingNumber, string Carrier);
public record ReducersEventSequenceShipmentSummary(string TrackingNumber, string Carrier, DateTimeOffset DispatchedAt);
[EventSequence("fulfillment-events")]
public class ReducersEventSequenceShipmentSummaryReducer : IReducerFor<ReducersEventSequenceShipmentSummary>
{
public ReducersEventSequenceShipmentSummary Dispatched(ReducersEventSequenceShipmentDispatched @event, ReducersEventSequenceShipmentSummary? current, EventContext context) =>
new(@event.TrackingNumber, @event.Carrier, context.Occurred);
}

View C# snippet source on GitHub

TypeScript selects the sequence through the reducer() decorator’s parameter. Kotlin and Java can use either @EventSequence or the eventSequence parameter on @Reducer. Use the client tab’s configuration shape; the parameter-based form is shown below.

When you are already using the [Reducer] attribute to set a custom identifier or other options, use its eventSequence parameter instead of adding a separate [EventSequence] attribute:

using Cratis.Chronicle.Events;
using Cratis.Chronicle.Reducers;
[EventType]
public record ReducersEventSequenceReducerAttributeShipmentDispatched(string TrackingNumber, string Carrier);
public record ReducersEventSequenceReducerAttributeShipmentSummary(string TrackingNumber, string Carrier, DateTimeOffset DispatchedAt);
[Reducer(id: "shipment-summary", eventSequence: "fulfillment-events")]
public class ReducersEventSequenceReducerAttributeShipmentSummaryReducer : IReducerFor<ReducersEventSequenceReducerAttributeShipmentSummary>
{
public ReducersEventSequenceReducerAttributeShipmentSummary Dispatched(ReducersEventSequenceReducerAttributeShipmentDispatched @event, ReducersEventSequenceReducerAttributeShipmentSummary? current, EventContext context) =>
new(@event.TrackingNumber, @event.Carrier, context.Occurred);
}

View C# snippet source on GitHub

Both approaches produce the same result. Prefer [Reducer(eventSequence: ...)] when you are already customizing the reducer with other parameters on that attribute.

Use [EventLog] when you want to be explicit that the reducer reads from the default event log, even when event types in the assembly carry a [EventStore] attribute pointing elsewhere:

using Cratis.Chronicle.Events;
using Cratis.Chronicle.EventSequences;
using Cratis.Chronicle.Reducers;
[EventType]
public record ReducersEventSequenceLogOrderPlaced(Guid OrderId);
public record ReducersEventSequenceLocalOrderSummary(int OrderCount, DateTimeOffset LastOrderAt);
[EventLog]
public class ReducersEventSequenceLocalOrderSummaryReducer : IReducerFor<ReducersEventSequenceLocalOrderSummary>
{
public ReducersEventSequenceLocalOrderSummary Placed(ReducersEventSequenceLogOrderPlaced @event, ReducersEventSequenceLocalOrderSummary? current, EventContext context)
{
var count = current?.OrderCount ?? 0;
return new ReducersEventSequenceLocalOrderSummary(count + 1, context.Occurred);
}
}

View C# snippet source on GitHub

[EventLog] explicitly selects the default log instead of inferring an inbox from event-store metadata. Use the event-log sequence name when configuring the same selection through a sequence parameter.

For outbox-to-inbox subscriptions between event stores, including automatic inbox routing and observer-level [EventStore] usage, see Subscribe Reducers to External Event Stores.

  • When you need to read from a specific sequence other than the inferred one
  • To suppress automatic inbox routing for a reducer that handles foreign events
  • For reducers that target a specialized or partitioned event stream
  • When an explicit sequence name improves readability and makes intent clear