PYTHON · LOCUST · comparison
Find the bottleneck.
Measure the repair.
One catalogue. The same price-service pool. Compare repeated item lookups with one batch request, under the same workload.
A deliberately modelled service, measured on one host. This report demonstrates the testing method; it does not estimate production capacity.
| Implementation | Requests | RPS | Catalogue p95 ms | Errors % |
|---|---|---|---|---|
| broken | 1190 | 79.3 | 737.1 | 0.0 |
| fixed | 10785 | 719.0 | 15.4 | 0.0 |
DIAGNOSIS
Too many dependency calls per catalogue
The broken catalogue fetches prices one item at a time. The fixed catalogue fetches the same prices in one batch. Both use the same eight-slot pool and simulated downstream I/O. Under load, queued work raises latency and can exhaust the pool wait timeout.
Check catalogue latency against pool activity and waiting requests. Read checkout separately: an aggregate percentile can conceal a critical operation.
Server signals over time
Mint: broken · Blue: fixed · Dashed line: start of the measured window
BROKEN IMPLEMENTATION
Thresholds exceeded
p95 exceeds threshold: GET /products
| Operation | Requests | Failures | p50 ms | p95 ms | p99 ms | All RPS | Successful RPS |
|---|---|---|---|---|---|---|---|
| DELETE /carts/[id] | 126 | 0 | 1.3 | 2.9 | 3.2 | 8.4 | 8.4 |
| GET /orders/[id] | 126 | 0 | 1.5 | 3.3 | 4.1 | 8.4 | 8.4 |
| GET /products | 434 | 0 | 712.1 | 737.1 | 751.2 | 28.9 | 28.9 |
| GET /products/[id] | 126 | 0 | 26.0 | 34.1 | 34.8 | 8.4 | 8.4 |
| POST /carts | 126 | 0 | 1.7 | 3.0 | 3.4 | 8.4 | 8.4 |
| POST /carts/[id]/checkout | 126 | 0 | 29.4 | 31.1 | 32.0 | 8.4 | 8.4 |
| POST /carts/[id]/items | 126 | 0 | 1.5 | 2.8 | 3.7 | 8.4 | 8.4 |
Stages
| Window | Target users | Requests | p95 ms | Errors % |
|---|---|---|---|---|
| 0–15 s | 24 | 1190 | 722.9 | 0.0 |
requests.csv · metrics.csv · summary.json · locust.html · locust.log
FIXED IMPLEMENTATION
Within configured thresholds
No configured threshold was exceeded in this measurement.
| Operation | Requests | Failures | p50 ms | p95 ms | p99 ms | All RPS | Successful RPS |
|---|---|---|---|---|---|---|---|
| DELETE /carts/[id] | 1102 | 0 | 1.8 | 4.3 | 6.1 | 73.5 | 73.5 |
| GET /orders/[id] | 1101 | 0 | 2.0 | 4.3 | 6.3 | 73.4 | 73.4 |
| GET /products | 4183 | 0 | 12.5 | 15.4 | 19.5 | 278.9 | 278.9 |
| GET /products/[id] | 1099 | 0 | 12.4 | 14.9 | 21.3 | 73.3 | 73.3 |
| POST /carts | 1100 | 0 | 2.0 | 4.6 | 6.2 | 73.3 | 73.3 |
| POST /carts/[id]/checkout | 1100 | 0 | 12.7 | 16.2 | 20.2 | 73.3 | 73.3 |
| POST /carts/[id]/items | 1100 | 0 | 2.0 | 4.4 | 6.1 | 73.3 | 73.3 |
Stages
| Window | Target users | Requests | p95 ms | Errors % |
|---|---|---|---|---|
| 0–15 s | 24 | 10785 | 14.7 | 0.0 |
requests.csv · metrics.csv · summary.json · locust.html · locust.log
How to interpret this run
Warm-up requests are excluded by request start time. Requests completing after the planned window are excluded from the summary; the raw CSV retains drained completions. Percentiles use nearest rank on raw completed requests, including errors. RPS counts completed requests per measured second, not unique customers. The task mix weights browsing four to one against purchasing; this is not an HTTP request ratio.
Locust is a closed workload: slower responses reduce the offered rate. Unfinished and drained requests are absent from percentiles. User targets are not guaranteed simultaneous active requests. Use separate generators and an arrival-rate workload before making a capacity commitment.
Pool counters cover the whole run, including warm-up. Server samples arrive roughly once per second. The demo retains orders until the stand exits; memory and database growth during soak need to be interpreted with that retention policy.
Run environment and thresholds
{
"profile": "comparison",
"started": 1791555140.7115724,
"measurement_start": 1791555143.7115724,
"finished": 1791555158.8300514,
"duration_seconds": 18,
"thresholds": {
"max_error_ratio": 0.01,
"max_p95_ms": 500,
"min_requests": 30,
"required_routes": [
"GET /products",
"POST /carts/[id]/checkout",
"GET /orders/[id]"
]
},
"stages": [
{
"until_seconds": 15,
"users": 24
}
],
"warmup_seconds": 3,
"spawn_rate": 24,
"think_seconds": 0.05,
"generator_cpu_warning": false,
"mode": "fixed",
"python": "3.12.14",
"platform": "Linux-7.0.0-34-generic-x86_64-with-glibc2.43",
"locust": "2.46.7",
"app_workers": 1,
"generator_processes": 1,
"same_host": true,
"locust_exit_code": 0
}