---
title: "Prove one request cannot stall the site · Agent Wranglers"
url: https://agentwranglers.se/playbook/testing/non-functional-tests/single-request-stall
id: TST-54
level: Required
risk: outage
updated: 2026-10-22
tokens: 1192
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Prove one request cannot stall the site

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [Non-functional tests](https://agentwranglers.se/playbook/testing/non-functional-tests.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers.md). Updated 2026-10-22.

- ID: TST-54
- Level: Required
- Chapter: [Non-functional tests](https://agentwranglers.se/playbook/testing/non-functional-tests.md)
- Rule: No single request, however large, may make other requests wait. Test each expensive endpoint alone while a second client fetches a small page every second.
- Check: During each heavy request, a small page keeps answering within 200 ms, or twice its normal time when that is slower. An outside check stays green. The script exits with an error otherwise.
- Risk: The app down or unusable
- How: One request that builds a large file and compresses it inside the only worker blocks every other visitor. The proxy then answers 504, but the app keeps working, so the whole site stays down until it finishes. Find the most expensive endpoints from `Server-Timing` headers, traces or response sizes. Fix any that stall the site by building the file ahead of time, as [Build large exports ahead of time](https://agentwranglers.se/playbook/scaling/background-jobs-and-queues/build-exports-ahead.md) says. Or move the work out of the request, as [Move slow work out of the request](https://agentwranglers.se/playbook/scaling/background-jobs-and-queues/slow-work-off-requests.md) says. Run the test in CI against the built app on staging, so a new slow endpoint cannot ship.

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### JavaScript example

```js
const SMALL_PAGE = 'https://staging.example.com/contact';
const HEAVY_REQUEST = 'https://staging.example.com/export/orders.csv';
const LIMIT_MS = 200;
const PROBE_INTERVAL_MS = 1000;

async function timedFetch(url) {
  const start = performance.now();
  await (await fetch(url)).arrayBuffer();
  return performance.now() - start;
}

let heavyDone = false;
const heavy = timedFetch(HEAVY_REQUEST).finally(() => { heavyDone = true; });
let slowest = 0;
while (!heavyDone) {
  slowest = Math.max(slowest, await timedFetch(SMALL_PAGE));
  await new Promise(resolve => setTimeout(resolve, PROBE_INTERVAL_MS));
}
await heavy;
if (slowest > LIMIT_MS) throw new Error(`The small page took ${Math.round(slowest)} ms during the heavy request`);
```

### Python example

```python
import threading
import time

import httpx

SMALL_PAGE = "https://staging.example.com/contact"
HEAVY_REQUEST = "https://staging.example.com/export/orders.csv"
LIMIT_SECONDS = 0.2
PROBE_INTERVAL_SECONDS = 1


def test_a_heavy_request_does_not_stall_small_pages():
    heavy = threading.Thread(target=httpx.get, args=(HEAVY_REQUEST,), kwargs={"timeout": 120})
    heavy.start()
    slowest = 0.0
    while heavy.is_alive():
        start = time.monotonic()
        httpx.get(SMALL_PAGE, timeout=10)
        slowest = max(slowest, time.monotonic() - start)
        time.sleep(PROBE_INTERVAL_SECONDS)
    assert slowest < LIMIT_SECONDS
```

## Sources

- [Don't block the Node.js event loop](https://nodejs.org/en/learn/asynchronous-work/dont-block-the-event-loop)
- [OWASP Denial of Service Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Denial_of_Service_Cheat_Sheet.html)

## Related rules

- TST-53 [Run load tests from a written runbook](https://agentwranglers.se/playbook/testing/non-functional-tests/load-test-runbook.md) in Testing
- SCL-39 [Build large exports ahead of time](https://agentwranglers.se/playbook/scaling/background-jobs-and-queues/build-exports-ahead.md) in Scaling
- SCL-16 [Move slow work out of the request](https://agentwranglers.se/playbook/scaling/background-jobs-and-queues/slow-work-off-requests.md) in Scaling

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/testing/non-functional-tests/single-request-stall">Agent Wranglers testing playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Run load tests from a written runbook](https://agentwranglers.se/playbook/testing/non-functional-tests/load-test-runbook.md)
- Next: [Check accessibility in every build](https://agentwranglers.se/playbook/testing/non-functional-tests/accessibility-in-ci.md)
- [Non-functional tests](https://agentwranglers.se/playbook/testing/non-functional-tests.md)
