TriggerAction.Enqueue, no trigger registration).
For step-by-step instructions on configuring and using queues, see Use Queues. For DLQ management, see Manage Failed Triggers.
Queue Modes
Topic-based queues
Register consumers for a topic and emit events to it. Messages are delivered using fan-out per function: every distinct function subscribed to a topic receives a copy of each message. When multiple replicas of the same function are running, they compete on a shared per-function queue — only one replica processes each message.- Register a consumer with
registerTrigger({ type: 'queue', function_id: 'my::handler', config: { topic: 'order.created' } }). This subscribes the handler to that topic. - Emit events by calling
trigger({ function_id: 'enqueue', payload: { topic: 'order.created', data: payload } })ortrigger({ function_id: 'enqueue', payload: { topic, data }, action: TriggerAction.Void() })for fire-and-forget. Theenqueuefunction fans out the payload to every subscribed function. - Action on the trigger: the handler receives the
dataas its input. Optionalqueue_configon the trigger controls per-subscriber retries and concurrency.
If functions
A and B both subscribe to topic order.created, each message published to that topic is delivered to both A and B. If function A has 3 replicas running, only one replica of A processes each message — they compete on a shared queue. This gives you pub/sub-style fan-out with the durability and retry guarantees of a queue.Named queues
Define queues iniii-config.yaml, then enqueue function calls directly. No trigger registration needed.
- Define queues in
queue_configs(see Configuration). - Enqueue a function call with
trigger({ function_id: 'orders::process', payload, action: TriggerAction.Enqueue({ queue: 'payment' }) }). The engine routes the job to the named queue and invokes the function when a worker consumes it. - Action on the trigger: the target function receives
payloadas its input. Retries, concurrency, and FIFO are configured centrally iniii-config.yaml.
When to use which
| Topic-based | Named queues | |
|---|---|---|
| Producer | Calls trigger({ function_id: 'enqueue', payload: { topic, data } }) | Calls trigger({ function_id, payload, action: TriggerAction.Enqueue({ queue }) }) |
| Consumer | Registers registerTrigger({ type: 'queue', config: { topic } }) | No registration — function is the target |
| Delivery | Fan-out: each subscribed function gets every message; replicas compete | Single target function per enqueue call |
| Config | Optional queue_config on trigger | queue_configs in iii-config.yaml |
| Use case | Durable pub/sub with retries and fan-out | Direct function invocation with retries, FIFO, DLQ |
Named queues use the
Enqueue trigger action. For a full comparison of synchronous, Void, and Enqueue invocation modes, see Trigger Actions.Sample Configuration
Configuration
A map of named queue configurations. Each key is the queue name referenced in
TriggerAction.Enqueue({ queue: 'name' }). Define a queue named default in config for the common case; reference it as TriggerAction.Enqueue({ queue: 'default' }).The transport adapter for queue persistence and distribution. Defaults to
modules::queue::BuiltinQueueAdapter when not specified.Queue Configuration
Each entry inqueue_configs defines an independent named queue with its own retry, concurrency, and ordering settings.
Maximum delivery attempts before routing the job to the dead-letter queue. Defaults to
3.Maximum number of jobs processed simultaneously from this queue. Defaults to
10. For FIFO queues, the engine overrides this to prefetch=1 to guarantee ordering — see the note below.Delivery mode:
standard (concurrent, default) or fifo (ordered within a message group).Required when
type is fifo. The JSON field in the job payload whose value determines the ordering group. Jobs with the same group value are processed strictly in order. The field must be present and non-null in every enqueued payload.Base retry backoff in milliseconds. Applied with exponential scaling:
backoff_ms × 2^(attempt − 1). Defaults to 1000.Worker poll interval in milliseconds. Defaults to
100.Adapters
modules::queue::BuiltinQueueAdapter
Built-in in-process queue. No external dependencies. Suitable for single-instance deployments — messages are not shared across engine instances.Persistence strategy:
in_memory (lost on restart) or file_based (durable across restarts). Defaults to in_memory.Path to the queue store directory. Required when
store_method is file_based.modules::queue::RedisAdapter
Uses Redis as the queue backend for topic-based pub/sub. Enables message distribution across multiple engine instances.The URL of the Redis instance to connect to.
modules::queue::RabbitMQAdapter
Uses RabbitMQ as the queue backend. Supports durable delivery, retries, and dead-letter queues across multiple engine instances. The engine owns consumer loops, retry acknowledgement, and backoff logic — RabbitMQ is used as a transport only. Retry uses explicit ack + republish to a retry exchange with anx-attempt header, keeping compatibility with both classic and quorum queues.
The AMQP URL of the RabbitMQ instance to connect to.
Queue naming in RabbitMQ
For each named queue defined inqueue_configs, iii creates the following RabbitMQ resources:
| Resource | Format | Example (payment) |
|---|---|---|
| Main exchange | iii.__fn_queue::<name> | iii.__fn_queue::payment |
| Main queue | iii.__fn_queue::<name>.queue | iii.__fn_queue::payment.queue |
| Retry exchange | iii.__fn_queue::<name>::retry | iii.__fn_queue::payment::retry |
| Retry queue | iii.__fn_queue::<name>::retry.queue | iii.__fn_queue::payment::retry.queue |
| DLQ exchange | iii.__fn_queue::<name>::dlq | iii.__fn_queue::payment::dlq |
| DLQ queue | iii.__fn_queue::<name>::dlq.queue | iii.__fn_queue::payment::dlq.queue |
Each named queue creates six RabbitMQ objects to support delayed retry and dead-lettering. For the design rationale, see Queue Architecture.
Topic-based queue naming in RabbitMQ
For topic-based queues, iii uses a fanout exchange per topic. Each subscribed function gets its own queue and DLQ bound to the exchange:| Resource | Format | Example (topic order.created, function notify::email) |
|---|---|---|
| Fanout exchange | iii.<topic>.exchange | iii.order.created.exchange |
| Per-function queue | iii.<topic>.<function_id>.queue | iii.order.created.notify::email.queue |
| Per-function DLQ | iii.<topic>.<function_id>.dlq | iii.order.created.notify::email.dlq |
Adapter Comparison
| BuiltinQueueAdapter | RabbitMQAdapter | RedisAdapter | |
|---|---|---|---|
| Retries | Yes | Yes | No |
| Dead-letter queue | Yes | Yes | No |
| FIFO ordering | Yes | Yes | No |
| Named queue consumption | Yes | Yes | No (publish only) |
| Topic-based pub/sub | Yes | Yes | Yes |
| Multi-instance | No | Yes | Yes |
| External dependency | None | RabbitMQ | Redis |
For practical guidance on which adapter to use in different deployment scenarios, see Use Queues — Choosing an Adapter.
Builtin Functions
The queue module registers the following functions automatically when it initializes. These are callable viatrigger() from any SDK or via the iii trigger CLI command.
enqueue
Publishes a message to a topic-based queue. The message is fanned out to every distinct function subscribed to that topic. Replicas of the same function compete on a shared per-function queue.| Field | Type | Description |
|---|---|---|
topic | string | The topic to publish to (required, non-empty) |
data | any | The payload delivered to each subscribed function |
null on success.
iii::queue::redrive
Moves all messages from a named queue’s dead-letter queue back to the main queue. Each message gets its attempt counter reset to zero. Input:| Field | Type | Description |
|---|---|---|
queue | string | The named queue whose DLQ should be redriven (required, non-empty) |
| Field | Type | Description |
|---|---|---|
queue | string | The queue name that was redriven |
redriven | number | The number of messages moved back to the main queue |
For a complete guide on inspecting DLQ messages before redriving, see Manage Failed Triggers.