---
title: "Hold normal load for hours to find leaks · Agent Wranglers"
url: https://agentwranglers.se/playbook/testing/non-functional-tests/soak-tests
updated: 2026-10-21
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Hold normal load for hours to find leaks

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). Updated 2026-10-21.

- ID: TST-51
- Level: Recommended
- Chapter: [Non-functional tests](https://agentwranglers.se/playbook/testing/non-functional-tests)
- Rule: Before a launch, and after changes to caching, connections or background jobs, run the average load for four hours or more. Fail when response times or memory keep rising.
- How: Run the [load test](https://agentwranglers.se/playbook/testing/non-functional-tests/load-tests) first, so you know the service holds its peak. Then hold the average daily load, not the peak, for hours. Some leaks show only with time. Memory, open connections, file handles, disk and queues grow until the service falls over. Watch the server's metrics during the run. Compare the last 30 minutes with the first 30 minutes after warm-up. The response time budget and the memory ceiling come from the load test rule. Run it against staging, never production. Use the result to set [headroom](https://agentwranglers.se/playbook/operations/capacity-and-cost/headroom).
- Check: The soak run lasts four hours or more at the average load. The 95th percentile response time in its last 30 minutes is within 10 percent of the first 30 minutes after warm-up. Memory, open connections and disk use grow less than 10 percent over the same span. The script exits with an error otherwise.

## 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
// k6 run soak.js
import http from 'k6/http';
import { check } from 'k6';

export const options = {
  stages: [
    { duration: '10m', target: 50 },
    { duration: '4h', target: 50 },
    { duration: '5m', target: 0 },
  ],
  thresholds: { http_req_failed: ['rate<0.01'] },
};

export default function () {
  const res = http.get('https://staging.example.com/products');
  check(res, { 'status is 200': r => r.status === 200 });
}
```

### Python example

```python
# locust -f soak.py --headless --users 50 --spawn-rate 5 --run-time 4h --host https://staging.example.com
from locust import HttpUser, between, task

WARM_UP_SAMPLES = 10
WINDOW_SAMPLES = 30
MAX_GROWTH = 1.10

class Shopper(HttpUser):
    wait_time = between(1, 5)

    @task
    def browse_products(self):
        self.client.get("/products")

def grew_too_much(samples_per_minute: list[float]) -> bool:
    early = samples_per_minute[WARM_UP_SAMPLES:WARM_UP_SAMPLES + WINDOW_SAMPLES]
    late = samples_per_minute[-WINDOW_SAMPLES:]
    return sum(late) / len(late) > MAX_GROWTH * sum(early) / len(early)
```

## Sources

- [k6 soak testing](https://grafana.com/docs/k6/latest/testing-guides/test-types/soak-testing/)

## Related rules

- [Test load against a budget](https://agentwranglers.se/playbook/testing/non-functional-tests/load-tests) in Testing
- [Keep headroom](https://agentwranglers.se/playbook/operations/capacity-and-cost/headroom) in Operations
- [Use Locust for load tests](https://agentwranglers.se/playbook/stack/testing-and-code-quality/locust) in Software choices

**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/soak-tests">Agent Wranglers testing playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Fuzz every parser of untrusted input](https://agentwranglers.se/playbook/testing/non-functional-tests/fuzz-parsers)
- [Non-functional tests](https://agentwranglers.se/playbook/testing/non-functional-tests)
