Queue

The queue system connects asynchronous message publishers, drivers, queues, consumers, and handler functions.

This page is a configuration and behavior reference. YAML fences are fragments for an existing entry list unless they show a complete document; external-driver examples assume the broker or AWS-compatible service already exists.

Architecture

flowchart LR
    P[Publisher] --> D[Driver]
    D --> Q[Queue]
    Q --> C[Consumer]
    C --> W[Worker Pool]
    W --> F[Function]
  • Driver — Backend implementation (memory, AMQP, or SQS)
  • Queue — Logical queue bound to a driver
  • Consumer — Connects a queue to a handler with concurrency settings
  • Worker pool — Concurrent message processors

Multiple queues can share a driver. Multiple consumers can process from the same queue.

Entry Kinds

Kind Description
queue.driver.memory In-memory queue driver
queue.driver.amqp AMQP (RabbitMQ) driver
queue.driver.sqs AWS SQS driver (also LocalStack, ElasticMQ)
queue.queue Queue declaration with driver reference
queue.consumer Consumer that processes messages

Driver Configuration

Memory Driver

The in-process driver is intended for development and single-node deployments and has no external dependencies.

- name: memory_driver
  kind: queue.driver.memory
  lifecycle:
    auto_start: true

AMQP Driver

For RabbitMQ and AMQP 0-9-1 compatible brokers.

- name: amqp_driver
  kind: queue.driver.amqp
  url: "amqp://guest:guest@localhost:5672/"
  vhost: "/"
  connection_name: "wippy-service"
  heartbeat: "10s"
  connection_timeout: "30s"
  reconnect_delay: "1s"
  reconnect_max_delay: "30s"
  default_message_ttl: "1h"
  default_queue_expiry: "24h"
  prefetch_count: 10
  lifecycle:
    auto_start: true
Field Type Default Description
url string amqp://guest:guest@localhost:5672/ Broker URL
vhost string - Virtual host override
connection_name string - Identifier shown in broker UI
auth_mechanism string PLAIN PLAIN, EXTERNAL (mTLS), or AMQPLAIN
heartbeat duration - Keep-alive interval
connection_timeout duration - Dial timeout
reconnect_delay duration 1s Initial reconnect backoff
reconnect_max_delay duration 30s Max reconnect backoff
default_message_ttl duration - Per-message expiration used when a publisher does not set one
default_queue_ttl duration - Default queue-level message TTL (x-message-ttl)
default_queue_expiry duration - Default unused-queue expiration (x-expires)
prefetch_count int - Channel-level prefetch ceiling
frame_size int - AMQP frame size limit
channel_max int - Max channels per connection
tls object - TLS settings (see below)

Configure TLS under tls:

  tls:
    enabled: true
    server_name: "rabbit.example.com"
    cert: ${env:app.env:amqp_cert}
    key:  ${env:app.env:amqp_key}
    ca:   ${env:app.env:amqp_ca}
    insecure_skip_verify: false

cert/key/ca carry PEM content — inline, via file://, or via a ${env:NAME} placeholder resolved through the env registry. insecure_skip_verify disables certificate verification (development only). Legacy cert_env/key_env/ca_env directives also read the environment registry, but preserve an inline or zero value when the lookup is missing or empty; modern placeholders without defaults fail on missing variables. The legacy directives are deprecated.

SQS Driver

For AWS SQS and SQS-compatible endpoints (LocalStack, ElasticMQ). Credentials, region, and other AWS SDK settings come from a shared config.aws resource.

- name: aws_config
  kind: config.aws
  region: us-east-1
  access_key_id: ${env:app:AWS_ACCESS_KEY_ID}
  secret_access_key: ${env:app:AWS_SECRET_ACCESS_KEY}

- name: sqs_driver
  kind: queue.driver.sqs
  config: app:aws_config
  endpoint: "http://localhost:9324"
  message_retention_period: 86400
  default_delay_seconds: 0
  lifecycle:
    auto_start: true
Field Type Default Description
config Registry ID required config.aws resource providing region and credentials
endpoint string - Custom endpoint URL (LocalStack, ElasticMQ); omit for real AWS
message_retention_period int - Queue-level retention in seconds (60–1209600), set as a queue attribute on create. Omit to leave the AWS default of 345600 (4 days).
default_delay_seconds int 0 Default delivery delay applied on CreateQueue (0–900)
disable_message_checksum_validation bool false Disable SQS message checksum checks on send/receive
use_fips bool false Use FIPS-compliant endpoints
use_dual_stack bool false Use dual-stack (IPv4 + IPv6) endpoints

Queues are auto-created by the driver on first use. Use SQS-prefixed headers to address SQS-specific fields on publish: sqs.delay_seconds, sqs.message_group_id, and sqs.message_deduplication_id map to typed SQS message fields. All other headers (neutral keys like correlation_id and content_type, plus any sqs.message_attributes.* keys) are carried verbatim as SQS message attributes.

Queue Configuration

- name: tasks
  kind: queue.queue
  driver: app.queue:memory_driver
  codec: json/plain
  queue_name: "app_tasks"
  driver_options:
    memory:
      max_length: 500
  dead_letter:
    queue: app.queue:tasks_dlq
    max_attempts: 5
Field Type Required Description
driver Registry ID Yes Queue driver
codec string No Wire encoding for message bodies. Defaults to json/plain (see Codecs)
queue_name string No External queue name (defaults to entry name)
driver_options object No Per-driver sub-bag, keyed by driver kind
dead_letter.queue Registry ID No Queue ID for failed messages (accepted but not yet enforced by any built-in driver)
dead_letter.max_attempts int No Attempts before routing to DLQ (accepted but not yet enforced by any built-in driver)

Driver Options

Keys under driver_options are scoped by driver name. A driver reads only its own sub-bag — other keys are dormant, which lets a single queue entry declare settings for multiple drivers if needed.

memory:

Key Description
max_length Bounded buffer size (0 or unset = default 1000)

amqp:

Key Description
durable Survive broker restart
auto_delete Delete when last consumer detaches
message_ttl Per-queue message TTL override
queue_expiry Unused-queue expiration
max_length Max messages retained

Codecs

The codec selects how a message body is serialized before it is handed to the broker. It is a payload format string and defaults to json/plain:

Codec Format
json/plain JSON (default)
application/msgpack MessagePack

The AMQP driver sets a matching content-type (application/json or application/msgpack) on published messages. An unknown codec fails when the queue is declared, not at publish time.

Consumer Configuration

- name: task_consumer
  kind: queue.consumer
  queue: app.queue:tasks
  func: app.queue:task_handler
  concurrency: 4
  prefetch: 20
  auto_ack: false
  driver_options:
    amqp:
      consumer_tag: "worker-1"
      exclusive: false
  lifecycle:
    auto_start: true
    requires:
      - app.queue:tasks
Field Default Description
queue required Queue registry ID
func required Handler function registry ID
concurrency 1 Parallel worker count
prefetch 10 Shared delivery-buffer size; AMQP also applies it as the channel QoS prefetch count
auto_ack false Backend-specific auto-ack option; for AMQP, true asks the broker to acknowledge on delivery
driver_options - Per-driver sub-bag (same structure as queue)

amqp consumer options:

Key Description
exclusive Single-consumer queue access
no_local Reject messages published on the same connection
no_wait Don't wait for broker confirmation on subscribe
consumer_tag Identifier for this subscription
Consumers respect call context and can be subject to security policies. Configure actor and policies at the lifecycle level. See Security.

Worker Pool

Workers run concurrently:

concurrency: 3, prefetch: 10

1. Driver delivers up to 10 messages to the shared buffer
2. 3 workers pull from the buffer and can each hold an active delivery
3. As workers finish, buffer refills
4. Backpressure when all workers busy and buffer full

Handler Function

Consumer handlers receive the decoded message body as the first argument. Use queue.message() to access delivery metadata (id, headers).

local queue = require("queue")
local logger = require("logger")

local function main(body)
    local msg, msg_err = queue.message()
    if msg_err then return nil, msg_err end
    local message_id, id_err = msg:id()
    if id_err then return nil, id_err end
    local correlation_id, header_err = msg:header("correlation_id")
    if header_err then return nil, header_err end

    logger:info("processing", {
        id = message_id,
        correlation_id = correlation_id
    })

    local ok, err = process_task(body)
    if err then
        return nil, err  -- nack: redelivery per driver
    end
    return true          -- ack: remove from queue
end

return { main = main }
- name: task_handler
  kind: function.lua
  source: file://task_handler.lua
  method: main
  modules:
    - queue
    - logger

Acknowledgment

Unless the handler settles explicitly, the consumer settles from the function invocation result:

Handler Result Action
Any plain return value (including false) Ack
nil, err return Nack (redeliver per driver)
Raised error Nack

Ordinary return values, including false, do not select acknowledgment behavior. Call msg:ack() or msg:nack() to settle explicitly. Settlement is single-shot: whichever call lands first wins.

Dead-Letter Routing

Dead-letter routing is not yet implemented. The dead_letter block (see Queue Configuration) is accepted in config, but no built-in driver currently counts attempts, routes nacked messages to the configured DLQ, or sets x_dead_letter_* headers. A nacked message is redelivered per the driver's own policy. The x_* header namespace is reserved for future DLQ bookkeeping, so publishers should avoid setting x_* headers.

Publishing Messages

From Lua code:

local queue = require("queue")

local published, publish_err = queue.publish("app.queue:tasks", {
    id = "task-123",
    action = "process",
    data = payload
})
if publish_err then return nil, publish_err end
return published

See Queue Module for the Lua publishing and message API.

Graceful Shutdown

On consumer stop:

  1. Stop accepting new deliveries
  2. Cancel worker contexts
  3. Wait for in-flight messages (with timeout)
  4. Return error if workers don't finish in time

See Also