Skip to content

Event Sequence

By default, reactors 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 [Reactor] attribute.

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

using Cratis.Chronicle.Events;
using Cratis.Chronicle.EventSequences;
using Cratis.Chronicle.Reactors;
[EventType]
public record EventSequenceShipmentDispatched(string TrackingNumber);
[EventSequence("fulfillment-events")]
public class EventSequenceShipmentReactor : IReactor
{
public Task ShipmentDispatched(EventSequenceShipmentDispatched @event, EventContext context) =>
NotifyCarrierAsync(@event.TrackingNumber);
Task NotifyCarrierAsync(string trackingNumber) => Task.CompletedTask;
}

TypeScript reaches the same result through the reactor() decorator’s eventSequenceId parameter shown below rather than a separate attribute. Kotlin, Java, and Elixir don’t currently support targeting a non-default event sequence at all.

When you are already using the [Reactor] 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.Reactors;
[EventType]
public record EventSequenceReactorAttributeShipmentDispatched(string TrackingNumber);
[Reactor(id: "shipment-reactor", eventSequence: "fulfillment-events")]
public class EventSequenceReactorAttributeShipmentReactor : IReactor
{
public Task ShipmentDispatched(EventSequenceReactorAttributeShipmentDispatched @event, EventContext context) =>
NotifyCarrierAsync(@event.TrackingNumber);
Task NotifyCarrierAsync(string trackingNumber) => Task.CompletedTask;
}

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

Use [EventLog] when you want to be explicit that the reactor 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.Reactors;
[EventType]
public record EventSequenceLogOrderPlaced(Guid OrderId);
[EventLog]
public class EventSequenceLocalAuditReactor : IReactor
{
public Task OrderPlaced(EventSequenceLogOrderPlaced @event, EventContext context) =>
WriteAuditAsync(@event.OrderId, context.Occurred);
Task WriteAuditAsync(Guid orderId, DateTimeOffset occurred) => Task.CompletedTask;
}

This convenience is C#-only — it exists to disambiguate against C#‘s [EventStore] attribute on event types, which the other clients don’t have.

For outbox-to-inbox subscriptions between event stores, including automatic inbox routing and observer-level [EventStore] usage, see Subscribe Reactors 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 reactor that handles foreign events
  • For reactors that target a specialized or partitioned event stream
  • When an explicit sequence name improves readability and makes intent clear