Scheduler
The scheduler global provides task scheduling APIs based on the WICG Scheduling APIs proposal ↗. Workers currently implement the scheduler.wait() method.
scheduler.wait() returns a Promise that resolves after a given number of milliseconds. It is an await-able alternative to setTimeout() that does not require a callback.
Like other timers in Workers, scheduler.wait() does not advance during CPU execution when deployed to Cloudflare. This is a security measure to mitigate against Spectre attacks. In local development, timers advance regardless of whether I/O occurs.
await scheduler.wait(delay);await scheduler.wait(delay, options);-
delaynumber- The number of milliseconds to wait before the returned Promise resolves.
-
optionsobject optional-
Optional configuration for the wait operation.
-
signalAbortSignal optional- An
AbortSignalthat cancels the wait. When the signal is aborted, the returned Promise rejects with anAbortError.
- An
-
A Promise<void> that resolves after delay milliseconds. If an AbortSignal is provided and aborted before the delay elapses, the Promise rejects with an AbortError.
Use scheduler.wait() to pause execution for a specified duration.
export default { async fetch(request) { // Wait for 1 second await scheduler.wait(1000); return new Response("Delayed response"); },};export default { async fetch(request): Promise<Response> { // Wait for 1 second await scheduler.wait(1000); return new Response("Delayed response"); },} satisfies ExportedHandler;Use scheduler.wait() to implement a delay between retry attempts. This example uses exponential backoff with jitter.
async function fetchWithRetry(url, maxAttempts = 3) { const baseBackoffMs = 100; const maxBackoffMs = 10000;
for (let attempt = 0; attempt < maxAttempts; attempt++) { try { return await fetch(url); } catch (err) { if (attempt + 1 >= maxAttempts) { throw err; } const backoffMs = Math.min( maxBackoffMs, baseBackoffMs * Math.random() * Math.pow(2, attempt), ); await scheduler.wait(backoffMs); } } throw new Error("unreachable");}
export default { async fetch(request) { const response = await fetchWithRetry("https://example.com/api"); return new Response(response.body, response); },};async function fetchWithRetry(url: string, maxAttempts = 3): Promise<Response> { const baseBackoffMs = 100; const maxBackoffMs = 10000;
for (let attempt = 0; attempt < maxAttempts; attempt++) { try { return await fetch(url); } catch (err) { if (attempt + 1 >= maxAttempts) { throw err; } const backoffMs = Math.min( maxBackoffMs, baseBackoffMs * Math.random() * Math.pow(2, attempt), ); await scheduler.wait(backoffMs); } } throw new Error("unreachable");}
export default { async fetch(request): Promise<Response> { const response = await fetchWithRetry("https://example.com/api"); return new Response(response.body, response); },} satisfies ExportedHandler;Use an AbortController to cancel a pending wait.
export default { async fetch(request) { const controller = new AbortController();
// Cancel the wait after 500ms setTimeout(() => controller.abort(), 500);
try { await scheduler.wait(5000, { signal: controller.signal }); return new Response("Wait completed"); } catch (err) { if (err instanceof DOMException && err.name === "AbortError") { return new Response("Wait was cancelled", { status: 408 }); } throw err; } },};export default { async fetch(request): Promise<Response> { const controller = new AbortController();
// Cancel the wait after 500ms setTimeout(() => controller.abort(), 500);
try { await scheduler.wait(5000, { signal: controller.signal }); return new Response("Wait completed"); } catch (err) { if (err instanceof DOMException && err.name === "AbortError") { return new Response("Wait was cancelled", { status: 408 }); } throw err; } },} satisfies ExportedHandler;- Timers —
setTimeout()andsetInterval()APIs - Performance and timers —
performance.now()and timer security behavior - AbortController and AbortSignal — cancel asynchronous operations
- WICG Scheduling APIs proposal ↗ — the specification this API is based on