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.
Delivery Guarantees
Section titled “Delivery Guarantees”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.
Designing for Idempotency
Section titled “Designing for Idempotency”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:
- Send-time idempotency keys: Pass an
idempotencyKeywhen 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",}) - 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.
Payload & Message Limits
Section titled “Payload & Message Limits”Keep your message payloads small and highly structured.
| Limit | Maximum | Description |
|---|---|---|
| Message Size | 128 KB | Each message must fit within Cloudflare Queues message size limits, including metadata. |
| Payload Format | JSON-serializable | Any valid JSON value (objects, arrays, strings, numbers, booleans, or null). |
| Batch Size (Send) | 100 messages | Recommended maximum for a single sendBatch call. |
| Batch Size (Consume) | 100 messages | The maximum batch size leased by a single consumer invocation (default: 10). |
Retention & Dead Letters
Section titled “Retention & Dead Letters”Messages cannot sit in a queue indefinitely.
| Metric | Default | Allowed Range | Description |
|---|---|---|---|
| Message Retention | 7 days | 1 to 14 days | Time a message can live in the pending queue before being permanently deleted. |
| DLQ Retention | 14 days | 1 to 14 days | Retention duration for failed messages routed to a dead-letter queue. |
| Max Attempts | 5 | 1 or greater | The maximum number of retries before moving a message to the DLQ. |
Layeron enforces a 14-day maximum in app configuration.
Consumer Configurations
Section titled “Consumer Configurations”You can configure how your queue consumer processes messages to match your load and downstream service constraints:
Concurrency
Section titled “Concurrency”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.
Visibility Timeout
Section titled “Visibility Timeout”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
visibilityTimeoutSecondsis always larger than the maximum time your consumer requires to complete its heaviest work.
Retry Backoff Calculations
Section titled “Retry Backoff Calculations”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:
Fixed Backoff
Section titled “Fixed Backoff”Delays between attempts are uniform:
Delay = initialDelaySeconds
Exponential Backoff (Default)
Section titled “Exponential Backoff (Default)”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 = 5seconds. - Attempt 2: Failed. Retry delay =
5 * 2^1 = 10seconds. - Attempt 3: Failed. Retry delay =
5 * 2^2 = 20seconds. - Attempt 4: Failed. Retry delay =
5 * 2^3 = 40seconds. - … growing exponentially up to a maximum cap of
300seconds (5 minutes).