Skip to content

Tagging Reactors

Tags provide a way to organize and categorize your reactors for better discoverability and management. By applying the [Tag] attribute to your reactor classes, you can assign one or more tags that describe the purpose or domain of the reactor.

[Tag] and [Tags] label the reactor itself. They do not filter which appended events the reactor handles. For event filtering based on appended metadata, see Filter reducers and reactors by tag, Filter reducers and reactors by event source type, and Filter reducers and reactors by event stream type.

You can tag reactors in multiple ways:

Apply a single tag to your reactor:

using Cratis.Chronicle;
using Cratis.Chronicle.Events;
using Cratis.Chronicle.Reactors;
[EventType]
public record TaggingReactorsOrderPlaced(string CustomerId, string OrderId);
public interface ITaggingReactorsEmailService
{
Task SendOrderConfirmation(string customerId, string orderId);
}
[Tag("Notifications")]
public class TaggingReactorsOrderConfirmationReactor(ITaggingReactorsEmailService emailService) : IReactor
{
public Task Placed(TaggingReactorsOrderPlaced @event, EventContext context) =>
emailService.SendOrderConfirmation(@event.CustomerId, @event.OrderId);
}

Use the params feature to specify multiple tags in a single attribute:

using Cratis.Chronicle;
using Cratis.Chronicle.Events;
using Cratis.Chronicle.Reactors;
[EventType]
public record TaggingReactorsCustomerRegistered(string Email, string Name);
public interface ITaggingReactorsWelcomeEmailService
{
Task SendWelcomeEmail(string email, string name);
}
[Tag("Notifications", "Customer", "Email")]
public class TaggingReactorsCustomerNotificationReactor(ITaggingReactorsWelcomeEmailService emailService) : IReactor
{
public Task Registered(TaggingReactorsCustomerRegistered @event, EventContext context) =>
emailService.SendWelcomeEmail(@event.Email, @event.Name);
}

Apply multiple [Tag] attributes:

using Cratis.Chronicle;
using Cratis.Chronicle.Events;
using Cratis.Chronicle.Reactors;
[EventType]
public record TaggingReactorsProductStockChanged(string ProductId, int NewQuantity);
public interface ITaggingReactorsInventoryApi
{
Task UpdateStock(string productId, int newQuantity);
}
[Tag("Integration")]
[Tag("ExternalAPI")]
[Tag("Inventory")]
public class TaggingReactorsInventorySyncReactor(ITaggingReactorsInventoryApi inventoryApi) : IReactor
{
public Task StockChanged(TaggingReactorsProductStockChanged @event, EventContext context) =>
inventoryApi.UpdateStock(@event.ProductId, @event.NewQuantity);
}

Combine both approaches:

using Cratis.Chronicle;
using Cratis.Chronicle.Events;
using Cratis.Chronicle.Reactors;
[EventType]
public record TaggingReactorsOrderShipped(string PhoneNumber, string TrackingNumber);
public interface ITaggingReactorsSmsService
{
Task SendShippingNotification(string phoneNumber, string trackingNumber);
}
[Tag("Notifications", "SMS")]
[Tag("Customer")]
public class TaggingReactorsSmsNotificationReactor(ITaggingReactorsSmsService smsService) : IReactor
{
public Task Shipped(TaggingReactorsOrderShipped @event, EventContext context) =>
smsService.SendShippingNotification(@event.PhoneNumber, @event.TrackingNumber);
}
  • Use meaningful names: Choose tag names that clearly describe the purpose or domain
  • Be consistent: Establish tag naming conventions across your organization
  • Don’t over-tag: Apply only relevant tags; too many can reduce their usefulness
  • Group related reactors: Use tags to group reactors that serve similar purposes

Here are some common patterns for tagging reactors:

using Cratis.Chronicle;
using Cratis.Chronicle.Reactors;
// By integration type
[Tag("Notifications", "ExternalAPI", "MessageQueue", "FileSystem")]
// By domain
[Tag("Sales", "Inventory", "Customer", "Shipping")]
// By communication channel
[Tag("Email", "SMS", "Push", "Webhook")]
// By purpose
[Tag("Integration", "Alerting", "Monitoring", "Automation")]
// By stakeholder
[Tag("Customer", "Operations", "Finance", "Support")]
public class TaggingReactorsCategoryExamplesReactor : IReactor;

Tags stored in the event store definition can be used for:

  • Filtering and searching for specific reactors
  • Organizing reactors in administrative interfaces
  • Generating documentation
  • Managing reactor deployments by tag
  • Monitoring and alerting based on tag groups
  • Controlling reactor activation by tag

Note: The specific querying capabilities depend on your Chronicle setup and tooling.