queue
v0.1.2Durable function queues - registers the `durable:subscriber` trigger type and the queue/DLQ service functions.
- macOS: arm64 · x64
- Linux: arm64 · armv7 · x64
- Windows: arm64 · x64 · x86
skill doc
queue
The queue worker provides durable topic delivery for iii. Register a consumer
with a durable:subscriber trigger, publish with iii::durable::publish, and
the worker persists messages, retries failed deliveries, moves exhausted jobs to
DLQ, and exposes redrive/discard inspection functions.
Install it with iii worker add queue. The built-in iii-queue worker must be
removed from the engine config before this worker starts because both would own
the same durable:subscriber trigger type.
When to Use
- A topic event must be processed reliably by a subscribed function.
- A failed consumer should retry automatically before the message lands in DLQ.
- You need to inspect, redrive, or discard dead-lettered messages.
- Local or single-instance durable queues are enough, using in-memory storage for development or file-backed storage for restart survival.
Boundaries
- Not fire-and-forget broadcast. Use
pubsubwhen missed events are acceptable. - Three transports ship today:
builtin(in-process, full DLQ/retry/fifo),redis(pub/sub only, no DLQ), andrabbitmq(full: retry/DLQ/priority/fifo). Thebridgeadapter is not ported — it was engine-internal and is superseded by the engine'sQueueEnqueuercut (MOT-3829). - Engine
TriggerAction.Enqueue/ named function queues require the separateQueueEnqueuerengine cut. Until that lands, useiii::durable::publishanddurable:subscribertriggers for this standalone worker. - File-backed mode survives worker restarts. In-memory mode loses pending jobs
on restart or transport hot-swap. An unreachable
redis/rabbitmqtarget at boot fails the boot (no fallback tobuiltin). fifomode is strictly serial — there is no grouped-fifo partitioning bygroup_idlike the engine'sGroupedFifoWorker.- This worker carries work items, not key/value or stream state. Use
stateorstreamfor those.
Functions
iii::durable::publish: publish a JSON payload to a queue/topic. Input accepts{ "queue": "...", "data": ... }and also acceptstopicas an alias.iii::queue::redrive: move all DLQ messages for a queue back to the main queue. Input acceptsqueueortopic.iii::queue::redrive_message: move one DLQ message back bymessage_id.iii::queue::discard_message: purge one DLQ message bymessage_id.engine::queue::list_topics: list known queue topics.engine::queue::topic_stats: returndepth,consumer_count, anddlq_depthfor one topic.engine::queue::dlq_topics: list DLQ topics with message counts.engine::queue::dlq_messages: browse DLQ messages withoffsetandlimit.
Reactive Triggers
Bind a durable:subscriber trigger when a function should consume every
message published to a queue/topic with retries and DLQ handling.
iii.registerTrigger({
type: 'durable:subscriber',
function_id: 'orders::process',
config: {
queue: 'orders.created',
max_retries: 3,
backoff_ms: 1000,
},
})Trigger config:
queue(required): topic/queue name to consume.topicis accepted as a compatibility alias.max_retries(default3): failed attempts before moving to DLQ.backoff_ms(default1000): base retry delay. Retries use the same exponential curve as the builtin queue:backoff_ms * 2^(attempts - 1).condition_function_id(optional): called before the handler; only explicitfalseskips the handler.
Configuration
Use the configuration worker entry named queue. The default is in-memory:
adapter:
name: builtinFor restart survival, use file-backed storage:
adapter:
name: builtin
config:
store_method: file_based
file_path: ./data/queue
save_interval_ms: 5000For pub/sub-only delivery against a shared Redis (no DLQ, no durability):
adapter:
name: redis
config:
redis_url: redis://localhost:6379For full retry/DLQ/priority/fifo delivery against RabbitMQ:
adapter:
name: rabbitmq
config:
amqp_url: amqp://localhost:5672
max_attempts: 3
prefetch_count: 10
queue_mode: standard
priority_field: priorityChanging the adapter config hot-swaps the transport and restarts every consumer — the new adapter is built first, so a bad config leaves the previous one serving. File-backed jobs survive by construction; in-memory jobs are lost, matching the builtin adapter's in-process durability profile.