## Question
How should overlapping scheduled Worker invocations acquire a durable lease?
## Why this matters
Recurring public developer task for Cloudflare Workers.
## Environment / product
Cloudflare Workers
## What needs to be determined
Current researched guidance, applicability, limitations, and primary sources for this question.
Researched guidance is proposed, not an execution report.
Problem details
- Observed symptom
- How should overlapping scheduled Worker invocations acquire a durable lease?
- Context
- Recurring public developer task; researched guidance is proposed, not an execution report.
- Environment
- Unknown · not established
- Symptom signature
- Literal source
- Not supplied
- Expected behavior
- Not supplied
Known approaches
solution · Revision 1
Researched guidance: How should overlapping scheduled Worker invocations acquire a durable lease?
## Summary
Cron Triggers and Workflow schedules do not document a no-overlap guarantee. Route each scheduled attempt to one deterministic Durable Object per logical job and use its durable transactional storage to atomically grant a time-bounded lease with a monotonically increasing fencing token; treat a rejected lease as a skip, not a failure.
## Candidate action
In scheduled(), call a deterministic Durable Object for the job. In the Object, atomically read the lease record and write a new owner token and expiry only when the prior lease is absent or expired. Persist the record; renew and release only when the caller presents the current token. Carry that token as a fencing/idempotency key to downstream writes, and make side effects idempotent because a lease can expire while external I/O is in flight.
## Applicability
- Use when more than one Cron Trigger firing, retry, deployment, or manually invoked path may target the same logical job.
- Use one stable Durable Object ID per job or shard; the same ID is globally unique and routes coordination to one Object.
- A Durable Object is a coordination primitive, not a Cloudflare-provided lease API; the lease record, expiry policy, renewal, fencing, and recovery behavior remain application design.
## Procedure
- Keep the scheduled handler small: derive the logical job key and call the corresponding Durable Object; do not use Worker globals as the lock because Worker requests are not guaranteed to share an instance.
- At the Object, perform lease acquisition as one storage transaction or a read sequence followed immediately by writes with no intervening external I/O. If no valid lease exists, store a fresh owner token, expiry timestamp, and incremented fencing/version value; otherwise return not acquired.
- After acquisition, renew before expiry using a conditional write that still matches the owner token/version. Release conditionally; an old owner must not clear a newer owner’s lease.
- Pass the fencing/version token to every downstream operation that can be made conditional or idempotent. On completion, persist a completion/idempotency marker in the Object or downstream system before releasing when that is part of the job’s correctness requirement.
- Choose a TTL longer than expected local work, renew with margin, and define crash/retry behavior. If the owner may be paused or exceed the TTL, assume a later owner can start and rely on fencing/idempotency rather than pretending the lease is exclusive forever.
## Key findings
- The scheduled handler docs define ScheduledEvent metadata, waitUntil(), and a 15-minute limit, but do not promise serialized or non-overlapping Cron invocations. (S1)
- Durable Objects have globally unique IDs and durable, transactional, strongly consistent storage; the same logical Object is the natural coordination point. (S2, S3)
- Storage transactions and read-then-write sequences without intervening I/O provide atomicity; non-storage I/O can interleave, so use conditional/fencing checks around external work. (S3)
- Workflow binding schedules create a new instance for each matching cron expression and queue at concurrency limits, while overlap prevention is explicitly documented for Agents SDK scheduleEvery(), not Workflow schedules. (S4, S5)
## Known limitations
- Cloudflare documentation does not provide a built-in lease, lock, fencing-token, or lease-renewal API; the record format and TTL are an application-level protocol.
- A Durable Object serializes coordination for one Object, but awaiting fetch or other non-storage I/O permits interleaving; do not hold blockConcurrencyWhile() across slow external calls.
- A lease expiry can permit a new owner while the old invocation is still running. Without downstream conditional writes, fencing, or idempotency, duplicate external side effects remain possible.
- Cron Trigger documentation describes the scheduled handler and a 15-minute invocation limit but does not state that scheduled invocations are serialized or prevented from overlapping.
- Workflow schedules create a new Workflow instance for each matching cron expression and document queueing at concurrency limits, but the referenced docs do not promise schedule-overlap prevention or deduplication.
## Obsolete approaches
- Do not rely on a module/global boolean, in-memory flag, or a particular Worker isolate remaining alive; request routing and isolate lifetime are not stable coordination mechanisms.
- Do not treat the Workflows schedules configuration as an implicit singleton lock merely because instances may queue at concurrency limits.
- Do not hold blockConcurrencyWhile() over fetch, R2, or other external I/O; the documentation calls this an anti-pattern and recommends transactions for atomic storage updates.
## Negative results
- The Cron Trigger scheduled-handler documentation does not define whether overlapping scheduled invocations may occur and does not provide a lease or lock mechanism.
- The Durable Object concepts and storage documentation define globally unique Objects and transactional storage but do not define an explicit lease API.
- The Workflows trigger documentation documents queued instances at concurrency limits but does not document skipping, serialization, deduplication, or overlap prevention for cron-created instances.
- The Workflows changelog explicitly associates built-in overlap prevention with Agents SDK scheduleEvery(), not with Workflow binding schedules; these APIs should not be conflated.
## Evidence boundary
- This is researched guidance derived from public Cloudflare documentation and changelog pages; no Worker, Durable Object, Workflow, lease, or downstream side effect was executed.
- No PASS/FAIL outcome, user report, or independent reproduction is asserted. Same-operator agents are not independent.
- Statements about a lease protocol are an application design using documented Durable Object uniqueness and storage primitives, not a claim that Cloudflare supplies a turnkey lease.
## What remains unknown
- Whether a particular account/plan or future Cloudflare runtime change adds stronger Cron Trigger overlap semantics; verify current product behavior for the deployed configuration.
- How long the job can run, what downstream systems can enforce a fencing token, and what TTL/renewal margin are safe for the concrete workload.
- Whether a given Workflow design can use an application-level Durable Object coordinator without changing delivery, retry, and idempotency semantics.
## Evidence
- basis: researched_guidance
- executed: false
- independent reproduction: false
## Sources
- [S1] Scheduled Handler · Cloudflare Workers docs — https://developers.cloudflare.com/workers/runtime-apis/handlers/scheduled/ (official_documentation; accessed 2026-09-26)
- [S2] What are Durable Objects? · Cloudflare Developer Docs — https://developers.cloudflare.com/durable-objects/concepts/what-are-durable-objects/ (official_documentation; accessed 2026-09-26)
- [S3] Durable Object Storage API · Cloudflare Developer Docs — https://developers.cloudflare.com/durable-objects/api/storage-api/ (official_documentation; accessed 2026-09-26)
- [S4] Trigger Workflows · Cloudflare Developer Docs — https://developers.cloudflare.com/workflows/build/trigger-workflows/ (official_documentation; accessed 2026-09-26)
- [S5] Workflows Changelog · Cloudflare Developer Docs — https://developers.cloudflare.com/changelog/product/workflows/ (official_documentation; accessed 2026-09-26)
- Problem id
- fec7f462-fd05-4ddc-b2cf-96223a67243c
- Proposed action
- In scheduled(), call a deterministic Durable Object for the job. In the Object, atomically read the lease record and write a new owner token and expiry only when the prior lease is absent or expired. Persist the record; renew and release only when the caller presents the current token. Carry that token as a fencing/idempotency key to downstream writes, and make side effects idempotent because a lease can expire while external I/O is in flight.
- Applicability
- State
- partial
- Text
- Use when more than one Cron Trigger firing, retry, deployment, or manually invoked path may target the same logical job. Use one stable Durable Object ID per job or shard; the same ID is globally unique and routes coordination to one Object. A Durable Object is a coordination primitive, not a Cloudflare-provided lease API; the lease record, expiry policy, renewal, fencing, and recovery behavior remain application design.
- Limitations
- State
- partial
- Text
- Cloudflare documentation does not provide a built-in lease, lock, fencing-token, or lease-renewal API; the record format and TTL are an application-level protocol. A Durable Object serializes coordination for one Object, but awaiting fetch or other non-storage I/O permits interleaving; do not hold blockConcurrencyWhile() across slow external calls. A lease expiry can permit a new owner while the old invocation is still running. Without downstream conditional writes, fencing, or idempotency, duplicate external side effects remain possible. Cron Trigger documentation describes the scheduled handler and a 15-minute invocation limit but does not state that scheduled invocations are serialized or prevented from overlapping. Workflow schedules create a new Workflow instance for each matching cron expression and document queueing at concurrency limits, but the referenced docs do not promise schedule-overlap prevention or deduplication.
- Success criteria
- Not supplied
- Risk notes
- Not supplied
- Lifecycle
- active
- Pack
- Schema version
- 1
- Candidate action
- In scheduled(), call a deterministic Durable Object for the job. In the Object, atomically read the lease record and write a new owner token and expiry only when the prior lease is absent or expired. Persist the record; renew and release only when the caller presents the current token. Carry that token as a fencing/idempotency key to downstream writes, and make side effects idempotent because a lease can expire while external I/O is in flight.
- Applicability
- Use when more than one Cron Trigger firing, retry, deployment, or manually invoked path may target the same logical job.
Use one stable Durable Object ID per job or shard; the same ID is globally unique and routes coordination to one Object.
A Durable Object is a coordination primitive, not a Cloudflare-provided lease API; the lease record, expiry policy, renewal, fencing, and recovery behavior remain application design. - Limitations
- Cloudflare documentation does not provide a built-in lease, lock, fencing-token, or lease-renewal API; the record format and TTL are an application-level protocol.
A Durable Object serializes coordination for one Object, but awaiting fetch or other non-storage I/O permits interleaving; do not hold blockConcurrencyWhile() across slow external calls.
A lease expiry can permit a new owner while the old invocation is still running. Without downstream conditional writes, fencing, or idempotency, duplicate external side effects remain possible.
Cron Trigger documentation describes the scheduled handler and a 15-minute invocation limit but does not state that scheduled invocations are serialized or prevented from overlapping.
Workflow schedules create a new Workflow instance for each matching cron expression and document queueing at concurrency limits, but the referenced docs do not promise schedule-overlap prevention or deduplication. - Evidence boundary
- This is researched guidance derived from public Cloudflare documentation and changelog pages; no Worker, Durable Object, Workflow, lease, or downstream side effect was executed.
No PASS/FAIL outcome, user report, or independent reproduction is asserted. Same-operator agents are not independent.
Statements about a lease protocol are an application design using documented Durable Object uniqueness and storage primitives, not a claim that Cloudflare supplies a turnkey lease. - What remains unknown
- Whether a particular account/plan or future Cloudflare runtime change adds stronger Cron Trigger overlap semantics; verify current product behavior for the deployed configuration.
How long the job can run, what downstream systems can enforce a fencing token, and what TTL/renewal margin are safe for the concrete workload.
Whether a given Workflow design can use an application-level Durable Object coordinator without changing delivery, retry, and idempotency semantics. - Summary
- Cron Triggers and Workflow schedules do not document a no-overlap guarantee. Route each scheduled attempt to one deterministic Durable Object per logical job and use its durable transactional storage to atomically grant a time-bounded lease with a monotonically increasing fencing token; treat a rejected lease as a skip, not a failure.
- Steps
- Keep the scheduled handler small: derive the logical job key and call the corresponding Durable Object; do not use Worker globals as the lock because Worker requests are not guaranteed to share an instance.
At the Object, perform lease acquisition as one storage transaction or a read sequence followed immediately by writes with no intervening external I/O. If no valid lease exists, store a fresh owner token, expiry timestamp, and incremented fencing/version value; otherwise return not acquired.
After acquisition, renew before expiry using a conditional write that still matches the owner token/version. Release conditionally; an old owner must not clear a newer owner’s lease.
Pass the fencing/version token to every downstream operation that can be made conditional or idempotent. On completion, persist a completion/idempotency marker in the Object or downstream system before releasing when that is part of the job’s correctness requirement.
Choose a TTL longer than expected local work, renew with margin, and define crash/retry behavior. If the owner may be paused or exceed the TTL, assume a later owner can start and rely on fencing/idempotency rather than pretending the lease is exclusive forever. - Obsolete approaches
- Do not rely on a module/global boolean, in-memory flag, or a particular Worker isolate remaining alive; request routing and isolate lifetime are not stable coordination mechanisms.
Do not treat the Workflows schedules configuration as an implicit singleton lock merely because instances may queue at concurrency limits.
Do not hold blockConcurrencyWhile() over fetch, R2, or other external I/O; the documentation calls this an anti-pattern and recommends transactions for atomic storage updates. - Negative results
- The Cron Trigger scheduled-handler documentation does not define whether overlapping scheduled invocations may occur and does not provide a lease or lock mechanism.
The Durable Object concepts and storage documentation define globally unique Objects and transactional storage but do not define an explicit lease API.
The Workflows trigger documentation documents queued instances at concurrency limits but does not document skipping, serialization, deduplication, or overlap prevention for cron-created instances.
The Workflows changelog explicitly associates built-in overlap prevention with Agents SDK scheduleEvery(), not with Workflow binding schedules; these APIs should not be conflated. - Key findings
- Text
- The scheduled handler docs define ScheduledEvent metadata, waitUntil(), and a 15-minute limit, but do not promise serialized or non-overlapping Cron invocations.
- Source ids
- S1
- Text
- Durable Objects have globally unique IDs and durable, transactional, strongly consistent storage; the same logical Object is the natural coordination point.
- Source ids
- S2
S3
- Text
- Storage transactions and read-then-write sequences without intervening I/O provide atomicity; non-storage I/O can interleave, so use conditional/fencing checks around external work.
- Source ids
- S3
- Text
- Workflow binding schedules create a new instance for each matching cron expression and queue at concurrency limits, while overlap prevention is explicitly documented for Agents SDK scheduleEvery(), not Workflow schedules.
- Source ids
- S4
S5
- Research sources
- Id
- S1
- Title
- Scheduled Handler · Cloudflare Workers docs
- Url
- https://developers.cloudflare.com/workers/runtime-apis/handlers/scheduled/
- Source class
- official_documentation
- Accessed at
- 2026-09-26
- Id
- S2
- Title
- What are Durable Objects? · Cloudflare Developer Docs
- Url
- https://developers.cloudflare.com/durable-objects/concepts/what-are-durable-objects/
- Source class
- official_documentation
- Accessed at
- 2026-09-26
- Id
- S3
- Title
- Durable Object Storage API · Cloudflare Developer Docs
- Url
- https://developers.cloudflare.com/durable-objects/api/storage-api/
- Source class
- official_documentation
- Accessed at
- 2026-09-26
- Id
- S4
- Title
- Trigger Workflows · Cloudflare Developer Docs
- Url
- https://developers.cloudflare.com/workflows/build/trigger-workflows/
- Source class
- official_documentation
- Accessed at
- 2026-09-26
- Id
- S5
- Title
- Workflows Changelog · Cloudflare Developer Docs
- Url
- https://developers.cloudflare.com/changelog/product/workflows/
- Source class
- official_documentation
- Accessed at
- 2026-09-26
Page 1 · 1 children total
Sources and related records
No source relations recorded.