Skip to content

Tagging Reducers

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

[Tag] and [Tags] label the reducer itself. They do not filter which appended events the reducer 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.

Kotlin and Java use repeatable @Tag annotations. TypeScript uses @tag(...) or @tags(...) on the reducer class; those labels are sent with its observer registration.

For self reducers, place descriptive tags on the read model itself. They remain observer labels, not append-time event tags or delivery filters.

You can tag reducers in multiple ways:

Apply a single tag to your reducer:

using Cratis.Chronicle;
using Cratis.Chronicle.Events;
using Cratis.Chronicle.Reducers;
[EventType]
public record TaggingReducersOrderPlaced(decimal TotalAmount);
public record TaggingReducersOrderAnalytics(int OrderCount, decimal TotalAmount);
[Tag("Analytics")]
public class TaggingReducersOrderAnalyticsReducer : IReducerFor<TaggingReducersOrderAnalytics>
{
public TaggingReducersOrderAnalytics Placed(TaggingReducersOrderPlaced @event, TaggingReducersOrderAnalytics? current, EventContext context) =>
new((current?.OrderCount ?? 0) + 1, (current?.TotalAmount ?? 0m) + @event.TotalAmount);
}

View C# snippet source on GitHub

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

using Cratis.Chronicle;
using Cratis.Chronicle.Reducers;
public record TaggingReducersSalesReport(decimal TotalSales);
[Tag("Analytics", "Reporting", "Dashboard")]
public class TaggingReducersSalesReportReducer : IReducerFor<TaggingReducersSalesReport>;

View C# snippet source on GitHub

Apply multiple [Tag] attributes:

using Cratis.Chronicle;
using Cratis.Chronicle.Reducers;
public record TaggingReducersComplianceReport(string Status);
[Tag("Analytics")]
[Tag("Compliance")]
[Tag("Auditing")]
public class TaggingReducersComplianceReportReducer : IReducerFor<TaggingReducersComplianceReport>;

View C# snippet source on GitHub

Combine both approaches:

using Cratis.Chronicle;
using Cratis.Chronicle.Reducers;
public record TaggingReducersExecutiveDashboard(int MetricCount);
[Tag("Analytics", "Reporting")]
[Tag("Executive")]
public class TaggingReducersExecutiveDashboardReducer : IReducerFor<TaggingReducersExecutiveDashboard>;

View C# snippet source on GitHub

  • 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 reducers: Use tags to group reducers that serve similar purposes

Here are some common patterns for tagging reducers:

using Cratis.Chronicle;
using Cratis.Chronicle.Reducers;
public record TaggingReducersCategoryExamples(Guid Id);
// By domain
[Tag("Sales", "Inventory", "Customer")]
// By purpose
[Tag("Analytics", "Reporting", "Dashboard", "Auditing")]
// By stakeholder
[Tag("Executive", "Operations", "Finance")]
// By data type
[Tag("Aggregates", "Summaries", "Metrics")]
public class TaggingReducersCategoryExamplesReducer : IReducerFor<TaggingReducersCategoryExamples>;

View C# snippet source on GitHub

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

  • Filtering and searching for specific reducers
  • Organizing reducers in administrative interfaces
  • Generating documentation
  • Managing reducer deployments by tag

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