Returning Side Effects from Reactor Handler Methods
Reactor handler methods can return side-effect events directly instead of taking a dependency on IEventLog. The framework automatically appends the returned events to the correct sequence after the handler completes.
Basic Usage
Section titled “Basic Usage”Return a single event directly from a handler method — synchronously or as a Task<T>:
using Cratis.Chronicle.Events;using Cratis.Chronicle.Reactors;
public class WarehouseReactor : IReactor{ // Synchronous — no async overhead when the result is already available public StockDecreased BookReserved(BookReserved @event, EventContext context) => new StockDecreased(@event.Isbn, 1);
// Asynchronous — use when you need to await something before producing the event public async Task<StockDecreased> BookReservedAsync(BookReserved @event, EventContext context) { var available = await FetchCurrentStockAsync(@event.Isbn); return new StockDecreased(@event.Isbn, available); }
Task<int> FetchCurrentStockAsync(string isbn) => Task.FromResult(0);}The returned event is appended to the event log using the EventSourceId from the incoming EventContext. No IEventLog injection required.
Multiple Side Effects
Section titled “Multiple Side Effects”Return IEnumerable<TEvent> to append several events in one handler call:
public IEnumerable<object> BookReserved(BookReserved @event, EventContext context) =>[ new StockDecreased(@event.Isbn, 1), new StockLow(@event.Isbn),];Reactor-Level Metadata Resolution
Section titled “Reactor-Level Metadata Resolution”Set metadata once on the reactor type so every returned event inherits it automatically.
ICanProvideEventSourceId
Section titled “ICanProvideEventSourceId”Implement this interface to supply a custom EventSourceId for all side-effect events from this reactor:
public class WarehouseReactor : IReactor, ICanProvideEventSourceId{ readonly string _warehouseId;
public WarehouseReactor(string warehouseId) => _warehouseId = warehouseId;
public EventSourceId GetEventSourceId() => _warehouseId;
public StockDecreased BookReserved(BookReserved @event, EventContext context) => new StockDecreased(@event.Isbn, 1);}ICanProvideSubject
Section titled “ICanProvideSubject”Implement this interface to attach a Subject (e.g. a user or principal) to appended events:
public class OrderReactor : IReactor, ICanProvideSubject{ readonly string _userId;
public OrderReactor(string userId) => _userId = userId;
public Subject GetSubject() => new Subject(_userId);}ICanProvideEventStreamId
Section titled “ICanProvideEventStreamId”Implement this interface to specify a runtime EventStreamId:
public class TenantReactor : IReactor, ICanProvideEventStreamId{ readonly string _tenantId;
public TenantReactor(string tenantId) => _tenantId = tenantId;
public EventStreamId GetEventStreamId() => _tenantId;}[EventStreamType] and [EventSourceType] Attributes
Section titled “[EventStreamType] and [EventSourceType] Attributes”Apply these attributes to the reactor class for a compile-time stream or source type:
[EventStreamType("warehouse")][EventSourceType("product")]public class WarehouseReactor : IReactor{ public StockDecreased BookReserved(BookReserved @event, EventContext context) => new StockDecreased(@event.Isbn, 1);}Priority Order
Section titled “Priority Order”| Metadata | Priority |
|---|---|
EventSourceId | ICanProvideEventSourceId → eventContext.EventSourceId |
EventStreamId | ICanProvideEventStreamId → [EventStreamId] attribute → null |
EventStreamType | [EventStreamType] attribute → null |
EventSourceType | [EventSourceType] attribute → null |
Subject | ICanProvideSubject → null |
Custom Return Type Handlers
Section titled “Custom Return Type Handlers”Extend the pipeline by registering a custom IReactorSideEffectHandler:
public class MyHandler : IReactorSideEffectHandler{ public bool CanHandle(ReactorContext reactorContext, object value) => value is MySpecialResult;
public async Task Handle(ReactorContext reactorContext, IEventStore eventStore, object value) { // process value }}
// Register in DIservices.AddSingleton<IReactorSideEffectHandler, MyHandler>();Supported Return Types
Section titled “Supported Return Types”| Return type | Handler invoked |
|---|---|
TEvent | EventResultHandler — appends single event |
Task<TEvent> | EventResultHandler — appends single event |
IEnumerable<TEvent> | EventsResultHandler — appends each event |
Task<IEnumerable<TEvent>> | EventsResultHandler |
void / Task | No side effects appended |