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].