queue handler of your App receives them in batches, with retries and an optional dead-letter queue. Use a queue for email, webhooks, upload processing, and fan-out.
celld, the Judt runtime, implements the Cloudflare Queues API, with one consumer for each queue in your App. For the features that celld doesn’t support, see Differences from Cloudflare.
Configure
Add aqueues object to the wrangler.json file with a producer and a consumer:
wrangler.json
binding: the name of the binding inenv.queue: the queue name.delivery_delay: a delay, in seconds, for each message that the binding sends. The maximum is 86,400.
Deploy refuses other keys. A consumer needs a
main entry module that exports a queue handler. Each queue has one consumer.
A dead-letter queue is an ordinary queue. You can add a consumer for it, or keep its messages for inspection.
Send messages
To send a message, call thesend method on the producer binding. To send many messages in one call, use the sendBatch method:
sendBatch calls.
A queue accepts a maximum of 256 concurrent producer calls. After that, the call throws. Catch the error and try again after a short delay.
Consume messages
Thequeue handler receives a batch. We recommend that you settle each message: call ack() when the work succeeds, and retry() when it fails.
index.js
id: the message ID. It doesn’t change between deliveries.timestamp: the time the message was sent.body: the message content.attempts: the delivery count, starting at 1.ack(): marks the message as done.retry({ delaySeconds }): returns the message to the queue.
batch.queue, the queue name. The batch.ackAll() and batch.retryAll() methods apply to all messages that aren’t settled.
The handler’s result decides what happens to messages that you don’t settle:
- If the handler returns without any settle calls, then celld acknowledges all messages.
- If the handler throws, then all messages that aren’t acknowledged go back to the queue.
retry_delay, or for the delaySeconds value that you pass to retry(). The preceding example computes an exponential backoff from msg.attempts.
After the number of retries in max_retries, the message goes to the dead_letter_queue. If the consumer has no dead-letter queue, then celld deletes the message.
Make handlers safe to repeat
Delivery is at least once. A message can run two times, for example after a crash beforeack(). Make each handler idempotent. Use msg.id as the idempotency key, for example in a UNIQUE column in D1, or in the Idempotency-Key header of an external API.
Delivery has no order. Retries, delays, and concurrent batches change the order of messages. If order matters, put a sequence number in each message, or send the work through a Durable Object.
Fan out from a Cron Trigger
A cron handler that processes many records can run past its time. Instead, let the cron handler select IDs and send them to a queue. The consumer does the slow work:index.js
slot field makes each job idempotent for each run, because controller.scheduledTime is the same on a retry. For more information, see Cron Triggers.
Limits
The following table lists the limits of a queue:
Each queue has one writer. For high volume, use more queues.
Differences from Cloudflare
The following Cloudflare Queues features aren’t available on celld:- Pull consumers
- The Queues HTTP API
- Consumers in other scripts
- R2 event notifications