Subscribe Reducers to External Event Stores
This page shows automatic inbox selection and subscription from event-store metadata on events or observers. For a subscription you configure explicitly, use explicit event-store subscriptions.
Self reducers use the same inbox routing. Their subscription event set comes from the owning registry’s selected static transitions; query methods and other helpers do not add subscription events.
Automatic Inbox Routing
Section titled “Automatic Inbox Routing”When all event types reduced by a reducer come from the same source event store, Chronicle routes the reducer to the matching inbox sequence automatically:
- Source event store:
fulfillment-service - Inbox sequence observed by the reducer:
inbox-fulfillment-service
This works when the source is declared on event types (or assembly) using [EventStore("...")], and no explicit event sequence is configured on the reducer.
using Cratis.Chronicle.Events;using Cratis.Chronicle.Reducers;
[EventType][EventStore("fulfillment-service")]public record ExternalReducerShipmentDispatched(Guid OrderId, string TrackingNumber);
public record ExternalReducerFulfillmentStatus(string Status, string TrackingNumber);
public class ExternalReducerFulfillmentStatusReducer : IReducerFor<ExternalReducerFulfillmentStatus>{ public ExternalReducerFulfillmentStatus Dispatched(ExternalReducerShipmentDispatched @event, ExternalReducerFulfillmentStatus? current, EventContext context) => new("Dispatched", @event.TrackingNumber);}Kotlin does not support this workflow yet.Java does not support this workflow yet.Elixir does not support this workflow yet.TypeScript does not support this workflow yet.Observer-Level EventStore for Missing Event Metadata
Section titled “Observer-Level EventStore for Missing Event Metadata”When event contracts cannot carry [EventStore] metadata, apply [EventStore] directly on the reducer.
Chronicle resolves the reducer to the inbox for that source event store and implicitly creates or reuses the outbox-to-inbox subscription.
using Cratis.Chronicle.Events;using Cratis.Chronicle.Reducers;
[EventType]public record ExternalReducerUserInvited(Guid UserId);
public record ExternalReducerUserTotals(int Count);
[EventStore("identity-service")][Reducer]public class ExternalReducerUserTotalsReducer : IReducerFor<ExternalReducerUserTotals>{ public ExternalReducerUserTotals Invited(ExternalReducerUserInvited @event, ExternalReducerUserTotals? current, EventContext context) => new((current?.Count ?? 0) + 1);}Kotlin does not support this workflow yet.Java does not support this workflow yet.Elixir does not support this workflow yet.TypeScript does not support this workflow yet.Implicit Combined Event Type Filtering
Section titled “Implicit Combined Event Type Filtering”For each source event store, Chronicle combines all reducer and reactor event types into one implicit subscription filter.
This means:
- You get one subscription per source event store.
- The filter is the union of handled event types from all participating observers.
- Only those event types are forwarded from source outbox to target inbox.
Explicit Event Sequence Is Not Allowed with Observer EventStore
Section titled “Explicit Event Sequence Is Not Allowed with Observer EventStore”When a reducer has [EventStore("...")], do not combine it with:
[EventSequence("...")][EventLog][Reducer(eventSequence: "...")]
This is invalid and fails:
- At runtime with
EventStoreCannotBeCombinedWithExplicitEventSequence. - At compile time with analyzer rule
CHR0014.
Forwarded metadata
Section titled “Forwarded metadata”Inbox forwarding now preserves append tags along with event-source and stream-route metadata. Tag filters can select forwarded events for classic and self reducers alike. Events forwarded by earlier releases that dropped tags remain untagged; upgrading does not backfill them.