Amba

Queues

Hand off background work to a queue and let a function consume it — decouple slow work from the request path, retry failures automatically, and dedupe with idempotency keys.

Queues let you push work out of the request path. Enqueue a job, return to your caller immediately, and a bound function processes the job in the background — with automatic retries and a dead-letter path when a job exhausts them. Use queues for anything that's slow or flaky: calling a third-party API, generating a file, fanning out notifications.

A queue is just a name. You bind one consumer function to it, then send jobs to it. Sends come from a function via ctx.queue.send or from the admin API; the binding is managed with amba functions consume.

Bind a consumer

A queue does nothing until a function is bound to consume it. Bind with the CLI:

amba functions consume orders process-order

This makes process-order the consumer for the orders queue. Queue names match ^[a-z][a-z0-9_-]*$ (≤58 chars). Pass --paused to create the binding paused — jobs dead-letter until you resume it.

MethodPathDescription
PUT/admin/projects/:projectId/queue/bindingsUpsert a binding. Body { queue_name, function_name, status? }.
GET/admin/projects/:projectId/queue/bindingsList bindings.
DELETE/admin/projects/:projectId/queue/bindings/:queue?confirm=:queueRemove a binding.
POST/admin/projects/:projectId/queue/sendEnqueue a job.

The CLI also exposes amba functions consumers list and amba functions consumers unbind <queue>. A binding's status is active or paused; rebinding the same queue overwrites the consumer and resets status to active.

Send a job

From inside a function, the runtime gives you ctx.queue.send:

export default {
  async fetch(req: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
    const order = await req.json();
    await ctx.queue.send('orders', order, { delay_seconds: 0 });
    return Response.json({ accepted: true }, { status: 202 });
  },
};

Or send via the admin API directly:

curl -X POST 'https://api.amba.dev/v1/admin/projects/$PROJECT_ID/queue/send' \
  -H 'Authorization: Bearer $AMBA_PAT' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "orders",
    "payload": { "order_id": "ord_123" },
    "delay_seconds": 0,
    "idempotency_key": "ord_123"
  }'
{ "data": { "job_id": "…", "deduplicated": false } }
FieldTypeRequiredNotes
namestringyesQueue name. Must already have a bound consumer.
payloadanynoThe job body, delivered verbatim to the consumer.
delay_secondsnumbernoNon-negative. Delays delivery by this many seconds.
idempotency_keystringno≤256 chars. A repeat within 24h returns the original job.

Sending to a queue with no bound consumer returns 400 UNKNOWN_QUEUE — bind one first. When you pass an idempotency_key, a duplicate send within 24 hours is collapsed: the response returns the original job_id with deduplicated: true and the job is not re-enqueued.

Consume a job

A bound consumer receives each job as an HTTP POST to its handler. The JSON body carries the queue name, your payload, and the enqueue time:

export default {
  async fetch(req: Request, env: Env): Promise<Response> {
    const { queue, payload, enqueued_at } = await req.json();
    // `queue` is "orders", `payload` is what you sent.
    await processOrder(payload);
    return new Response('ok'); // 2xx acknowledges the job
  },
};

The originating queue name is also available in the x-amba-queue request header.

Acknowledgement and retries

The consumer's HTTP status controls delivery:

  • 2xx — the job is acknowledged and removed.
  • 5xx, 408, or 429 — transient failure; the job is retried with backoff.
  • Other 4xx — the consumer rejected the payload's shape; the job is not retried and goes straight to the dead-letter path.

A job that exhausts its retries is dead-lettered rather than dropped. Paused bindings dead-letter immediately while paused — you can keep enqueuing while a consumer is drained.

From an agent

There are no dedicated queue MCP tools — queues are wired up through the function surface. An agent binds a consumer by deploying the function and calling the binding endpoint, and enqueues either from within a function (ctx.queue.send) or via POST /queue/send. See Functions for deploying the consumer.

On this page