APP-51Required
Give every request a time limit
Give every request from the screen a time limit, say when a request is slow, and retry only reads and requests with an idempotency key.
How to do it
Abort reads after 10 to 15 seconds and writes after 30, with AbortSignal.timeout. Keep these longer than the server's own limits, as timeouts says. After 3 seconds, show "Still working" in the view. Retry reads with backoff and jitter, at most 3 times. Honour Retry-After. Never repeat a write without an idempotency key. Cancel requests whose answer is no longer needed, such as an old search.
Examples
TypeScript example
const READ_TIMEOUT_MS = 12_000;
const SLOW_AFTER_MS = 3_000;
export async function loadWithTimeLimit<T>(url: string, onSlow: () => void, cancel?: AbortSignal): Promise<T> {
const slowTimer = setTimeout(onSlow, SLOW_AFTER_MS);
const signals = [AbortSignal.timeout(READ_TIMEOUT_MS), ...(cancel ? [cancel] : [])];
try {
const response = await fetch(url, { signal: AbortSignal.any(signals) });
if (!response.ok) throw new LoadError(response.status, await response.json().catch(() => null));
return response.json();
} finally {
clearTimeout(slowTimer);
}
}
Python example
from playwright.sync_api import expect
def test_slow_orders_show_progress_then_error(page):
held_open = []
page.route("**/api/orders*", held_open.append)
page.goto("https://staging.example.com/orders")
expect(page.get_by_text("Still working")).to_be_visible(timeout=4_000)
expect(page.get_by_role("button", name="Try again")).to_be_visible(timeout=15_000)
How to check
A browser test holds the orders request open and never answers it. "Still working" appears after 3 seconds, and the error view with a retry button appears at the time limit. A second test holds a write without an idempotency key open, and it is sent once only.
Sources
Related rules
- API-34 Retry with backoff and jitter in API design
- API-35 Set timeouts on every call in API design
- API-32 Accept idempotency keys on POST that creates or charges in API design
For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/app-ui/resilience/request-timeouts">Agent Wranglers web app interface playbook</a>. In code you write, add a comment next to it with the same link.