| name | automation-slice |
| description | Generate event-driven automation processors for AUTOMATION slices using Wolverine message handlers |
AUTOMATION Slice Skill
Overview
An AUTOMATION slice contains processors that react to events and trigger commands automatically. Automation processors appear in the processors array of a STATE_CHANGE slice.
Flow Pattern
Source Event → Wolverine IHandler → IMessageBus.PublishAsync() → Target Command
Java → C# / Critter Stack Mapping
| Java / Axon | C# / Critter Stack |
|---|
@EventHandler + @DisallowReplay | Wolverine handler method (event subscription) |
@ProcessingGroup | Wolverine subscription/routing |
CommandGateway.send() | Return cascaded command from handler |
implements Processor | implements IProcessor |
@DisallowReplay | Wolverine handles replay safety via outbox |
Key Characteristics
- Event-triggered — React to events published to the Wolverine bus
- Command-emitting — Cascade or publish the next command
- No state mutation — Processors orchestrate; they don't own state
- Replay-safe — Use Wolverine's outbox for at-least-once delivery guarantees
Code Generation Steps
Step 1: Identify Source Event and Target Command
Look at processor dependencies:
- OUTBOUND to COMMAND = the command this processor sends
- INBOUND from EVENT = the event that triggers this processor
Step 2: Create Processor Class
Location: <Context>/Slices/<SliceName>/Internal/<ProcessorName>Processor.cs
using SlicingWorkshop.Common;
using SlicingWorkshop.Domain.Commands;
using SlicingWorkshop.Events;
namespace SlicingWorkshop.<Context>.Slices.<SliceName>.Internal;
public class <ProcessorName>Processor : IProcessor
{
public static <TargetCommand> Handle(<SourceEvent> @event)
{
return new <TargetCommand>(
@event.AggregateId
);
}
}
When field mapping is needed:
public static <TargetCommand> Handle(<SourceEvent> @event)
{
return new <TargetCommand>(
@event.AggregateId,
UserId: @event.Owner
);
}
When async or side effects are needed:
public static async Task<<TargetCommand>> Handle(
<SourceEvent> @event,
IDocumentSession session)
{
return new <TargetCommand>(@event.AggregateId);
}
Step 3: Testing Processors
Location: <Context>/Slices/<SliceName>/Tests/<ProcessorName>ProcessorTests.cs
using SlicingWorkshop.Domain.Commands;
using SlicingWorkshop.Events;
using Xunit;
namespace SlicingWorkshop.<Context>.Slices.<SliceName>.Tests;
public class <ProcessorName>ProcessorTests
{
[Fact]
public void ShouldEmitCommandWhenEventReceived()
{
var aggregateId = Guid.NewGuid();
var @event = new <SourceEvent>(aggregateId);
var result = <ProcessorName>Processor.Handle(@event);
Assert.Equal(aggregateId, result.AggregateId);
}
}
Important Notes
- Prefer cascade returns — Return the next command directly from
Handle() rather than injecting IMessageBus. Wolverine publishes it transactionally via the outbox.
- Static handlers — Static
Handle() methods are preferred for pure processors with no dependencies.
- Wolverine outbox — Messages returned from handlers are sent via the outbox, ensuring at-least-once delivery even if the process crashes.
- No replay concerns — Unlike Axon's
@DisallowReplay, Wolverine's outbox pattern is safe by default.