Skip to content
// EFFECT DAYS 2026

CloudflarePersistedQueue

Runs persisted queues on the dedicated queue Durable Object class.

On this path one queue name is one Durable Object: the Worker encodes the queue name into a Durable Object name with the same length-prefix scheme as entities and resolves the object through the queue namespace binding. Items, their attempt counts, and their in-flight leases live on the object's SQLite storage behind its single alarm; a take with no available item waits inside the object until an offer, a retry, or an expired lease produces one.

Delivery is at-least-once: a taken item is leased for a bounded time and the lease is refreshed while the handler runs, so an item whose worker died is redelivered once the alarm watchdog expires the lease. Leasing an item counts an attempt, so a worker that dies still consumes one, and an expired lease on the last attempt marks the item failed. Offer delays use the object's clock and persist an initial visibility deadline; the alarm wakes waiting takers when that deadline expires.

This backs the DurableQueue user API; CloudflareCluster.layer already includes this layer.

A failed item stays hidden on the object for the configured retry delay, so it does not hold a consumer while other items are ready. An element that fails to decode is marked failed immediately.

PersistedQueue.layerCleanup is unsupported because the namespace binding cannot enumerate queue objects. Completed and failed rows remain retained for deduplication. A deduplicate: "untilExecuted" offer replaces such a row with a new element, which keeps only the latest failure.

3 exports Since v4.1.3 Source

Constructors

Since v4.1.3

Creates the PersistedQueueStore backed by the queue Durable Object namespace binding.

Signature

declare function make(options: LayerOptions): {
readonly cleanup: (options: {
readonly failedTimeToLive: Duration | undefined;
readonly timeToLive: Duration;
}) => Effect<void, PersistedQueueError>;
readonly offer: (options: {
readonly delay?: Duration;
readonly element: unknown;
readonly id: string;
readonly isCustomId: boolean;
readonly name: string;
}) => Effect<void, PersistedQueueError>;
readonly take: (options: {
readonly maxAttempts: number;
readonly name: string;
readonly retryDelay: (attempts: number) => Effect<Duration>;
}) => Effect<{
readonly attempts: number;
readonly element: unknown;
readonly id: string;
}, PersistedQueueError, Scope>;
}

Layers

Since v4.1.3

Layer that provides the PersistedQueueFactory backed by the queue Durable Object namespace binding.

Details

CloudflareCluster.layer already includes this layer; use it directly only when persisted queues are needed without the rest of the cluster.

Signature

declare function layer(options: LayerOptions): Layer<PersistedQueueFactory>

LayerOptions

interface
Since v4.1.3

The queue Durable Object namespace binding the store is built from.

Signature

interface LayerOptions {
readonly queueNamespace: DurableObjectNamespace;
}