CellB

Queues

A producer binding (env.<BINDING>.send(), sendBatch()) and a consumer (the Worker’s queue() handler), as configured under queues in the wrangler file. CellB runs celld’s own queue code (vendored unchanged), with the policy part of celld (celld_logic::queue, Rust) ported to TypeScript, so batching, retries, delays and dead-letter queues behave as on celld.

{
  "name": "queues",
  "main": "index.js",
  "compatibility_date": "2026-01-01",
  "queues": {
    "producers": [{ "binding": "JOBS", "queue": "example-jobs" }],
    "consumers": [
      {
        "queue": "example-jobs",
        "max_batch_size": 10,
        "max_batch_timeout": 5,
        "max_retries": 2,
        "dead_letter_queue": "example-jobs-dead-letter"
      },
      { "queue": "example-jobs-dead-letter" }
    ]
  }
}
export default {
  async fetch(request, env) {
    const job = {
      path: new URL(request.url).pathname,
      createdAt: new Date().toISOString(),
    };
    await env.JOBS.send(job);
    return Response.json({ queued: job });
  },

  async queue(batch) {
    for (const message of batch.messages) {
      if (batch.queue === "example-jobs-dead-letter") {
        console.log("dead job", message.body);
        message.ack();
        continue;
      }

      if (message.body.path.endsWith("/fail")) {
        console.log("retrying job", message.body, message.attempts);
        message.retry({ delaySeconds: 1 });
        continue;
      }

      console.log("processing job", message.body);
      message.ack();
    }
  },
};

This is celld’s queues example (conformance/celld-examples/queues), copied unchanged and run by the conformance suite on Node and in Chromium: a request to …/fail is retried twice, then lands in the dead-letter queue.

A queue is a cell, and its messages move with it

A queue lives in a cell __Queue:<id> with celld’s schema (__queue_messages, __queue_stats, __queue_meta, __queue_transfer_receipts), so pending messages move between celld and CellB with the cell. The queue cell’s alarm leases a batch; the host then runs the consumer’s queue() with celld’s batch object and posts the outcome back to the queue cell. max_concurrency defaults to celld’s ceiling, 250.

How it is checked

celld’s queues example and CellB’s queues-api and queues-details projects, on Node and in Chromium; e2e/p11f-celld-one-bucket.test.ts moves a queue’s data celld → CellB → celld.

What breaks

Errors carry celld’s messages: QUEUE_ERROR: ….