Skip to content

Guarantees & Limits

Layeron Queue gives your app an at-least-once background processing model with retries, dead letters, delayed delivery, and operational state you can inspect. Designing with these limits in mind keeps consumers predictable under retries and high traffic.


Layeron Queue uses at-least-once delivery.

This means a message can be delivered more than once under normal distributed systems conditions, including transient network failures, consumer crashes, or expired leases. Consumers must be safe to run more than once for the same business event.

To prevent duplicate processing of business actions, your consumer handlers should be idempotent—meaning processing the same message twice has the same outcome as processing it once.

Layeron Queue gives you two practical tools for idempotency:

  1. Send-time idempotency keys: Pass an idempotencyKey when sending a message. If the same key is sent again while Layeron still has the idempotency record, Layeron returns the existing message id instead of enqueueing a duplicate.
    Terminal window
    await reportsQueue.send({ reportId: "rep_100" }, {
    idempotencyKey: "rep_100_generation",
    })
  2. Consumer-side guardrails: Check inside your consumer whether the business action has already completed before performing secondary side effects, such as charging a customer or sending an email.

Keep your message payloads small and highly structured.

LimitMaximumDescription
Message Size128 KBEach message must fit within Cloudflare Queues message size limits, including metadata.
Payload FormatJSON-serializableAny valid JSON value (objects, arrays, strings, numbers, booleans, or null).
Batch Size (Send)100 messagesRecommended maximum for a single sendBatch call.
Batch Size (Consume)100 messagesThe maximum batch size leased by a single consumer invocation (default: 10).

Messages cannot sit in a queue indefinitely.

MetricDefaultAllowed RangeDescription
Message Retention7 days1 to 14 daysTime a message can live in the pending queue before being permanently deleted.
DLQ Retention14 days1 to 14 daysRetention duration for failed messages routed to a dead-letter queue.
Max Attempts51 or greaterThe maximum number of retries before moving a message to the DLQ.

Layeron enforces a 14-day maximum in app configuration.


You can configure how your queue consumer processes messages to match your load and downstream service constraints:

concurrency controls the maximum number of consumer handler instances that can run in parallel (default: 1, allowed: 1 to 100).

  • High Concurrency is great for CPU-light I/O bound jobs (e.g. hitting third-party external APIs).
  • Low Concurrency is recommended if your consumer writes heavy transactions to a database that has finite connection pools.

visibilityTimeoutSeconds represents the lock duration after a consumer receives a message (default: 30 seconds, minimum: 1 second).

  • During this window, no other concurrent consumers can see or process the same message.
  • If your consumer fails to finish and acknowledge (ack) the message within the visibility timeout, the lock expires and the message returns to the pending queue for another consumer to lease.
  • Ensure your visibilityTimeoutSeconds is always larger than the maximum time your consumer requires to complete its heaviest work.

When a consumer handler throws an error, the message is scheduled for a retry. Layeron calculates the delay between retry attempts using your configured retry parameters:

Delays between attempts are uniform: Delay = initialDelaySeconds

Delays double with each successive failure, capped at the maximum delay: Delay = min(initialDelaySeconds * 2^(attempt - 1), maxDelaySeconds)

Example with default values (initialDelaySeconds: 5, maxDelaySeconds: 300):

  • Attempt 1: Failed. Retry delay = 5 * 2^0 = 5 seconds.
  • Attempt 2: Failed. Retry delay = 5 * 2^1 = 10 seconds.
  • Attempt 3: Failed. Retry delay = 5 * 2^2 = 20 seconds.
  • Attempt 4: Failed. Retry delay = 5 * 2^3 = 40 seconds.
  • … growing exponentially up to a maximum cap of 300 seconds (5 minutes).