Pull consumers·续
The lease_id allows your pull consumer to explicitly acknowledge some, none or all messages in the batch or mark them for retry. If messages are not acknowledged or marked for retry by the consumer, then they will be marked for re-delivery once the visibility_timeout is reached. A lease_id is no longer valid once this timeout has been reached.
You can configure both batch_size and visibility_timeout when pulling from a queue:
batch_size(defaults to 5; max 100) - how many messages are returned to the consumer in each pull.visibility_timeout(defaults to 30 second; max 12 hours) - defines how long the consumer has to explicitly acknowledge messages delivered in the batch based on theirlease_id. Once this timeout expires, messages are assumed unacknowledged and queued for re-delivery again.
Concurrent consumers
You may have multiple HTTP clients pulling from the same queue concurrently: each client will receive a unique batch of messages and retain the "lease" on those messages up until the visibility_timeout expires, or until those messages are marked for retry.
Messages marked for retry will be put back into the queue and can be delivered to any consumer. Messages are not tied to a specific consumer, as consumers do not have an identity and to avoid a slow or stuck consumer from holding up processing of messages in a queue.
Multiple consumers can be useful in cases where you have multiple upstream resources (for example, GPU infrastructure), where you want to autoscale based on the backlog of a queue, and/or cost.
4. Acknowledge messages
Messages pulled by a consumer need to be either acknowledged or marked for retry.
To acknowledge and/or mark messages to be retried, make a HTTP POST request to /ack endpoint of your queue per the Queues REST API by providing an array of lease_id objects to acknowledge and/or retry:
index.jsjs
// POST /accounts/${CF_ACCOUNT_ID}/queues/${QUEUE_ID}/messages/ack with the lease_ids
let resp = await fetch(
`https://api.cloudflare.com/client/v4/accounts/${CF_ACCOUNT_ID}/queues/${QUEUE_ID}/messages/ack`,
{
method: "POST",
headers: {
"content-type": "application/json",
authorization: `Bearer ${QUEUES_API_TOKEN}`,
},
// If you have no messages to retry, you can specify an empty array - retries: []
body: JSON.stringify({
acks: [
{ lease_id: "lease_id1" },
{ lease_id: "lease_id2" },
{ lease_id: "etc" },
],
retries: [{ lease_id: "lease_id4" }],
}),
},
);
index.tsts
// POST /accounts/${CF_ACCOUNT_ID}/queues/${QUEUE_ID}/messages/ack with the lease_ids
let resp = await fetch(
`https://api.cloudflare.com/client/v4/accounts/${CF_ACCOUNT_ID}/queues/${QUEUE_ID}/messages/ack`,
{
method: "POST",
headers: {
"content-type": "application/json",
authorization: `Bearer ${QUEUES_API_TOKEN}`,
},
// If you have no messages to retry, you can specify an empty array - retries: []
body: JSON.stringify({
acks: [
{ lease_id: "lease_id1" },
{ lease_id: "lease_id2" },
{ lease_id: "etc" },
],
retries: [{ lease_id: "lease_id4" }],
}),
},
);
import json
from workers import fetch
# POST /accounts/${CF_ACCOUNT_ID}/queues/${QUEUE_ID}/messages/ack with the lease_ids
resp = await fetch(
f"https://api.cloudflare.com/client/v4/accounts/{CF_ACCOUNT_ID}/queues/{QUEUE_ID}/messages/ack",
method="POST",
headers={
"content-type": "application/json",
"authorization": f"Bearer {QUEUES_API_TOKEN}",
}, # If you have no messages to retry, you can specify an empty array - retries: []
body=json.dumps({
"acks": [
{"lease_id": "lease_id1"},
{"lease_id": "lease_id2"},
{"lease_id": "etc"},
],
"retries": [{"lease_id": "lease_id4"}],
}),
)
You may optionally specify the number of seconds to delay a message for when marking it for retry by providing a { lease_id: string, delay_seconds: number } object in the retries array:
{
"acks": [
{ "lease_id": "lease_id1" },
{ "lease_id": "lease_id2" },
{ "lease_id": "lease_id3" }
],
"retries": [{ "lease_id": "lease_id4", "delay_seconds": 600 }]
}
Additionally:
- You should provide every
lease_idin the request to the/ackendpoint if you are processing those messages in your consumer. If you do not acknowledge a message, it will be marked for re-delivery (put back in the queue). - You can optionally mark messages to be retried: for example, if there is an error processing the message or you have upstream resource pressure. Explicitly marking a message for retry will place it back into the queue immediately, instead of waiting for a (potentially long)
visibility_timeoutto be reached. - You can make multiple calls to the
/ackendpoint as you make progress through a batch of messages, but we recommend grouping acknowledgements to reduce the number of API calls required.
Queues aims to be permissive when it comes to lease IDs: if a consumer acknowledges a message by its lease ID after the visibility timeout is reached, Queues will still accept that acknowledgment. If the message was delivered to another consumer during the intervening period, it will also be able to acknowledge the message without an error.
Content types
Caution
When attaching a pull-based consumer to a queue, you should ensure that messages are sent with only a text, bytes or json content type.
The default content type is json.
Pull-based consumers cannot decode the v8 content type as it is specific to the Workers runtime.
When publishing to a queue that has an external consumer, you should be aware that certain content types may be encoded in a way that allows them to be safely serialized within a JSON object.
For both the json and bytes content types, this means that they will be base64-encoded (RFC 4648 ↗︎). The text type will be sent as a plain UTF-8 encoded string.
Your consumer will need to decode the json and bytes types before operating on the data.
Next steps
- Review the REST API documentation and schema for Queues.
- Learn more about how to make API calls to the Cloudflare API.
- Understand what limit apply when consuming and writing to a queue.
Was this helpful?
YesNo
On this page
{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/queues/configuration/pull-consumers/#page","headline":"Pull consumers","description":"Pull messages from a Cloudflare Queue over HTTP from any environment or language.","url":"https://developers.cloudflare.com/queues/configuration/pull-consumers/","inLanguage":"en","image":"https://developers.cloudflare.com/queues/configuration/pull-consumers/og.png?v=5134f1f74222aee3","dateModified":"2026-07-01","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"}}
description: Subscribe to events from Cloudflare services to build custom workflows, integrations, and logic with Workers. title: Event subscriptions image: https://developers.cloudflare.com/queues/event-subscriptions/og.png?v=4668ec09ec4a30e9
Documentation Index
Fetch the complete documentation index at: https://developers.cloudflare.com/queues/llms.txt
Use this file to discover all available pages before exploring further.
Docs