Skip to content

Attribute Reference

The Event Queue module uses two attributes to define queues and connect handlers.

[EventQueue]

Marks a static partial class as an event queue definition.

Property Type Default Description
QueueName string (required) Unique name identifying this queue
EventBaseType Type? null Optional base type constraint for events
Capacity int 10000 Channel capacity. 0 = unbounded.
MaxConcurrency int 1 Max parallel handlers. 1 = sequential, 0 = unlimited.
TimeoutMilliseconds int 0 Per-event handler timeout. 0 = no timeout.
MaxRetries int 7 Total retry attempts before dead-lettering. 1 = no retries.
SingleReader bool true Optimize channel for single reader
SingleWriter bool false Optimize channel for single writer
[EventQueue(QueueName = "orders", Capacity = 1000, MaxConcurrency = 4)]
public static partial class OrderEvents;

Capacity and backpressure

The default capacity of 10000 provides backpressure — Enqueue will wait if the channel is full, preventing OOM from fast-producer/slow-consumer scenarios. Set Capacity = 0 for an unbounded channel only when producers are trusted and events are lightweight.

Retry Configuration

The MaxRetries property controls the total number of attempts before an event is dead-lettered. The budget is split between immediate retries (in-memory, with exponential backoff) and delayed retries (re-enqueued via transport-level abandon):

MaxRetries Immediate Delayed Total Attempts
7 (default) 3 3 7 (1 initial + 3 + 3)
1 0 0 1 (dead-letter on first failure)
3 1 1 3
// Dead-letter on first failure (no retries)
[EventQueue(QueueName = "critical", MaxRetries = 1)]
public static partial class CriticalEvents;

// More aggressive retry (5 immediate + 4 delayed)
[EventQueue(QueueName = "resilient", MaxRetries = 10)]
public static partial class ResilientEvents;

Concurrency Configuration

The MaxConcurrency property controls how many events are processed in parallel:

Value Behavior
1 Sequential — events are processed one at a time (default)
N > 1 Parallel — up to N events processed concurrently via SemaphoreSlim
0 Unlimited — no concurrency limit
// Process up to 8 events in parallel
[EventQueue(QueueName = "notifications", MaxConcurrency = 8, Capacity = 5000)]
public static partial class NotificationEvents;

Ordering guarantees

With MaxConcurrency > 1, event processing order is not guaranteed. Use sequential mode (MaxConcurrency = 1) when ordering matters.

[EventQueueHandler<TRuntime>]

Links a static class of handler methods to a named queue and a runtime.

Property Type Description
QueueName string Must match an [EventQueue] declaration

The generic TRuntime parameter specifies which runtime provides capabilities to the handler Eff methods.

[EventQueueHandler<AppRuntime>(QueueName = "orders")]
public static class OrderEventHandlers
{
    // Each Handle method receives a specific event type
    public static Eff<AppRuntime, Unit> Handle(OrderPlaced evt) => ...
    public static Eff<AppRuntime, Unit> Handle(OrderCancelled evt) => ...
}

Handler method convention

Handler methods must be static, return Eff<TRuntime, Unit>, and accept a single event parameter. The parameter type determines which events are routed to that handler.

Integration events

Event Queue is for general-purpose in-process events. If your events need stable wire names and external transport support, see [IntegrationEventQueue] and [IntegrationEvent].