seda://¶
Asynchronous in-process named-queue messaging — Helix's SEDA implementation. A to: seda://name
enqueues the exchange on a bounded Go channel; one or more worker
goroutines on the consumer side drain it and dispatch into the route.
Reach for seda:// when you need decoupling (slow consumer must not
block fast producer), worker-pool fan-in, or pub/sub fanout to multiple
consumers — but you want it in-process, not via a real broker.
URI shape¶
<name> is the queue identifier. Identical names within one Component
share a single queue: the first CreateEndpoint call configures it,
later calls return the same Endpoint (and an explicit size mismatch is
rejected).
Parameters¶
Pulled directly from (*Component).Describe(). The flag triplet (blockWhenFull, discardWhenFull, offerTimeout) and the
Helix-native overflowPolicy shortcut both work; overflowPolicy wins
when both are set explicitly.
Queue sizing & workers¶
| Param | Type | Default | Side | Description |
|---|---|---|---|---|
name |
path | — | both | Queue identifier. |
size |
integer | 1000 |
both | Queue capacity. Set at creation; producer fills, consumer drains. |
bufferSize |
integer | 1000 |
both | Legacy alias for size. |
concurrentConsumers |
integer | 1 |
consumer | Number of worker goroutines draining the queue. |
concurrency |
integer | 1 |
consumer | Legacy alias for concurrentConsumers. |
limitConcurrentConsumers |
boolean | true |
consumer | Cap concurrentConsumers at 500 to prevent runaway pools. |
multipleConsumers |
boolean | false |
consumer | Pub/sub fan-out — every registered consumer receives a copy of each message. |
Producer overflow / no-consumer behaviour¶
| Param | Type | Default | Side | Description |
|---|---|---|---|---|
blockWhenFull |
boolean | false |
producer | Block (instead of erroring) when the queue is full. |
discardWhenFull |
boolean | false |
producer | Silently drop (instead of erroring) when the queue is full. Mutually exclusive with blockWhenFull. |
offerTimeout |
duration | 0 |
producer | When blockWhenFull=true, error out after this timeout instead of blocking forever. |
failIfNoConsumers |
boolean | false |
producer | Return ConsumerNotAvailableError when no consumer is registered. |
discardIfNoConsumers |
boolean | false |
producer | Silently drop when no consumer is registered. Mutually exclusive with failIfNoConsumers. |
overflowPolicy |
enum | fail |
producer | Helix-native single-knob policy: fail / block / drop / newest (drop-oldest). |
waitForTaskToComplete |
enum | IfReplyExpected |
producer | Wait policy — Always, Never, or IfReplyExpected (block on InOut, fire-forward on InOnly). |
timeout |
duration | 30s |
producer | Maximum wait when waitForTaskToComplete dictates a wait. |
Consumer¶
| Param | Type | Default | Side | Description |
|---|---|---|---|---|
pollTimeout |
duration | 1s |
consumer | Worker poll timeout — controls how quickly suspended-state and ctx-cancellation are observed. |
purgeWhenStopping |
boolean | false |
consumer | Discard pending messages on Stop instead of draining them. |
Durations accept Go format (30s, 500ms) or bare integer milliseconds
(30000).
Body shape¶
Producer enqueues the exchange. The consumer worker dequeues and
dispatches with the same In/Out/headers/properties. With
multipleConsumers=true each registered consumer gets its own
exchange.Copy().
Headers¶
seda:// sets no headers of its own.
Examples¶
Decouple a slow processor from a fast intake:
routes:
- id: intake
from: http-server://0.0.0.0:8080/events
steps:
- to: seda://to-process?size=10000&blockWhenFull=true
- id: worker
from: seda://to-process?concurrentConsumers=8
steps:
- to: postgres://events/insert
In-process pub/sub:
routes:
- id: emit
from: timer://heartbeat?period=10s
steps:
- to: seda://heartbeats?multipleConsumers=true
- id: ui-sub
from: seda://heartbeats?multipleConsumers=true
steps:
- to: ws-server://0.0.0.0:8081/heartbeat
- id: metrics-sub
from: seda://heartbeats?multipleConsumers=true
steps:
- to: log://heartbeat-metrics
InOut over seda (caller waits for reply):
Behavior notes¶
- Backpressure. Default policy is
fail(immediateQueueFullError). SetblockWhenFull=truefor natural backpressure, optionally withofferTimeoutto bound the wait. - Drop-oldest.
overflowPolicy=newestis Helix-only: when the queue is full, the oldest pending exchange is discarded and the new one takes its slot — useful for "always reflect latest" sensors. waitForTaskToCompletereply path. When a producer waits, the consumer'sOut(orIn, ifOutnot set) is copied back onto the caller's exchange after processing. Timeout firesseda: producer wait-for-reply timed out.- Suspend semantics.
Suspend()flips a flag but workers keep polling — pending queue messages stay queued; new ones are skipped untilResume(). - Queue sharing. Two endpoints with the same name share the queue
and the configuration set at first creation. Later URI calls with a
different
size(orbufferSize) error out — explicit so a typo doesn't silently double the buffer.
Source¶
pkg/component/seda/seda.go— Component, Endpoint, Producer, Consumer, error types (ConsumerNotAvailableError,QueueFullError).- Bench:
pkg/component/seda/seda_bench_test.go.
See also¶
- Synchronous in-process variant:
direct:// - For cross-process queues, use a real broker:
kafka://,nats://,amqp://,rabbitmq://.