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