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.
Using the [EventSequence] Attribute
Section titled “Using the [EventSequence] 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;}import io.cratis.chronicle.events.EventTypeimport io.cratis.chronicle.observation.EventSequenceimport io.cratis.chronicle.observation.Reactor
@EventType(id = "reactors-event-sequence-order-delivered")data class ReactorsEventSequenceOrderDelivered(val orderId: String)
@Reactor@EventSequence("outbox")class ReactorsEventSequenceDeliveryNotifications { fun delivered(event: ReactorsEventSequenceOrderDelivered) { // Observed from the "outbox" sequence, without giving up the conventional identifier. }}import io.cratis.chronicle.events.EventType;import io.cratis.chronicle.observation.EventSequence;import io.cratis.chronicle.observation.Reactor;
@EventType(id = "reactors-event-sequence-order-delivered")record ReactorsEventSequenceOrderDelivered(String orderId) {}
@Reactor@EventSequence("outbox")class ReactorsEventSequenceDeliveryNotifications { void delivered(ReactorsEventSequenceOrderDelivered event) { // Observed from the "outbox" sequence, without giving up the conventional identifier. }}TypeScript reaches the same result through the reactor() decorator’s eventSequenceId parameter, and Kotlin and Java through the eventSequence parameter on @Reactor — all shown under Using the [Reactor] Attribute below, rather than as a separate attribute. Elixir doesn’t currently support targeting a non-default event sequence at all.
Using the [Reactor] Attribute
Section titled “Using the [Reactor] Attribute”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;}import io.cratis.chronicle.events.EventTypeimport io.cratis.chronicle.observation.Reactor
@EventType(id = "reactors-event-sequence-order-shipped")data class ReactorsEventSequenceOrderShipped(val orderId: String)
@Reactor(id = "shipping-notifications", eventSequence = "outbox")class ReactorsEventSequenceShippingNotifications { fun shipped(event: ReactorsEventSequenceOrderShipped) { // Observed from the "outbox" sequence rather than the default event log. }}import io.cratis.chronicle.events.EventType;import io.cratis.chronicle.observation.Reactor;
@EventType(id = "reactors-event-sequence-order-shipped")record ReactorsEventSequenceOrderShipped(String orderId) {}
@Reactor(id = "shipping-notifications", eventSequence = "outbox")class ReactorsEventSequenceShippingNotifications { void shipped(ReactorsEventSequenceOrderShipped event) { // Observed from the "outbox" sequence rather than the default event log. }}import { eventType, reactor, EventContext } from '@cratis/chronicle';
@eventType()class EventSequenceReactorAttributeShipmentDispatched { constructor(readonly trackingNumber: string) {}}
@reactor('shipment-reactor', 'fulfillment-events')class EventSequenceReactorAttributeShipmentReactor { // Method name must be the exact camelCase of the event's class name - // Chronicle discovers handlers by name, not by parameter type. async eventSequenceReactorAttributeShipmentDispatched(event: EventSequenceReactorAttributeShipmentDispatched, context: EventContext): Promise<void> { await this.notifyCarrier(event.trackingNumber); }
private async notifyCarrier(trackingNumber: string): Promise<void> {}}Both approaches produce the same result. Prefer [Reactor(eventSequence: ...)] when you are already customizing the reactor with other parameters on that attribute.
Convenience: [EventLog]
Section titled “Convenience: [EventLog]”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;}Kotlin does not support this workflow yet.Java does not support this workflow yet.This convenience is C#-only — it exists to disambiguate against C#‘s [EventStore] attribute on event types, which the other clients don’t have.
External Event Store Inbox Routing
Section titled “External Event Store Inbox Routing”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 to Use [EventSequence] Explicitly
Section titled “When to Use [EventSequence] Explicitly”- 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