The Cloudflare Queues driver
Use the Cloudflare Queues driver to receive a Cloudflare queue in an app deployed to Workers. Cloudflare pushes each batch of messages to the Worker, and each message becomes its event for your subscribers, as with any queue (Queues):
// app.jadpoconnections: { warehouse_queue: { driver: Driver.cloudflare_queues queue: "warehouse-events" dead_letter_queue: "warehouse-events-dead" }}
- The connection.
driver: Driver.cloudflare_queuesnames one queue byqueue:, its name in Cloudflare, anddead_letter_queue:, another queue Cloudflare moves a message to once its retries are spent, so none is dropped: both required, both written out, since the consumer is written into the Wrangler file when the app is built, each lowercase letters, digits and dashes, starting and ending with a letter or digit, at most 63 characters (Jadpo's own form, since Wrangler checks no queue name and takes any text). The two differ, and no two connections name one queue. It takes nodomains:, since nothing butreceiving:reads it, and reaches no host, so the network report lists none. Problems areconnection.key_missing,connection.key_invalidandconnection.value_invalid;receiving:takes it as it takes a package's connection. - A batch. The Workers host's queue consumer, the Worker's
queue, starts the isolate asfetchdoes and hands each batch to the runtime's seam: the queue's name and each message's body, as text (a text body as sent, bytes as UTF-8 with an invalid sequence replaced, so it parks as unreadable, any other as its JSON), with the times it was handed over. An isolate that can't start, or whose stores aren't current, retries each message after the delay its attempts give, keeping nothing. Each message is read and kept as the tick keeps a fetched one ("How queues are received"), and answered in the batch's order: acknowledged once its event and id commit, as a repeat, or once parked; retried when the store can't take it now, after 10 seconds doubled for each earlier attempt, at most an hour. The host answers each message on its own, never the batch whole, then runs the kept events' deliveries after answering, inwaitUntiland handed on past its 30 seconds. Each batch with a message retried logsqueue.retriedwith the queue's name, how many and a code (not_started,not_received,store_unavailable), never a body. A batch from a queue the program doesn't receive is retried whole. - The tick. Nothing is fetched from a queue Cloudflare pushes; the
tick still reads again the parked messages an operator retried with
jadpo deliveries retry, as for any queue. - Long retries and the dead-letter queue. Every message the consumer retries is one the Worker can't take yet:
its isolate hasn't started, its stores are behind while a deploy
migrates them, or the store is unavailable; one it can read and can't
keep is parked, not retried. The delay doubles up to an hour and the consumer has 30
retries, about 22 hours: long enough to outlast a deploy's migration,
and short enough that the message reaches the dead-letter queue inside
the 24 hours a queue keeps a message on Workers' Free plan (4 days by
default on a paid one, at most 14), every value within Cloudflare's
limits (100 retries, a delay of at most 24 hours). The Worker consumes
the dead-letter queue too: each message it hands back is parked whole
in
jadpo_parked_messagesasdead_lettered, with its id and its event when they can be read and no event kept, and acknowledged, sojadpo deliverieslists it andretryhas the next tick read it again with the build running then; one the store can't park now is retried on the same schedule, 100 times, since a message whose retries are spent there is gone. So one queue's dead-letter queue is no other connection's queue or dead-letter queue (connection.value_invalid). A message whoseretry()throws isn't acknowledged by default: the handler throws once every message is answered, so Cloudflare hands again each one not acknowledged. - The Wrangler file. Each such queue is a consumer under
queues: { consumers: [] }: itsqueue,max_batch_size10 (as many as one receive asks a package's queue for),max_batch_timeout5 seconds,max_retries30 and itsdead_letter_queue; and the dead-letter queue is a consumer too, with the same batch, 100 retries, Cloudflare's most, and no dead-letter queue of its own. The setting names are Wrangler's own:jadpo buildwrites them into the Wrangler file as JSON, and Wrangler'sdeploy --dry-runaccepts it without a warning. - Natively. A server off Workers can't receive the binding: it reads
no message from the queue, only the parked ones an operator retried.
A native deployable that runs
Trigger.subscribers, where the app's queues are received, is refused the driver (Targets); a native server reads a Cloudflare queue through a package over its HTTP pull API instead.
Markdown for agents: /docs/the-cloudflare-queues-driver.md.Built from Jadpo main at a707efb.