Write load tests in Python. Run them at Rust speed.
Project description
LoadPilot
Write load tests in Python. Run them at Rust speed.
LoadPilot — CheckoutFlow [01:42] steady: 100/100 RPS
Requests/sec: 100.0 Total: 9,812
Errors: 0.0% Failed: 0
Latency:
p50: 12ms
p95: 28ms
p99: 41ms
max: 203ms
[████████████████████] 100%
LoadPilot is a load testing tool for teams that want to write scenarios in Python without the throughput ceiling of a pure-Python engine.
Scenarios are plain Python classes. HTTP execution runs in async Rust.
Install
pip install loadpilot
No Rust required — the coordinator binary is bundled in the wheel.
Supported platforms: Linux x86_64 · macOS Intel · macOS Apple Silicon · Windows x86_64
Quick Start
# scaffold a project
loadpilot init my-load-tests
cd my-load-tests
# run a scenario
loadpilot run scenarios/example.py --target https://your-api.example.com
Or run without arguments to pick a scenario interactively:
loadpilot run --target https://your-api.example.com
→ Getting Started in 5 minutes
Write a Scenario
from loadpilot import VUser, scenario, task, LoadClient
@scenario(rps=100, duration="2m", ramp_up="30s")
class CheckoutFlow(VUser):
def on_start(self, client: LoadClient):
resp = client.post("/auth/login", json={"user": "test", "pass": "secret"})
self.token = resp.json()["access_token"]
@task(weight=5)
def browse(self, client: LoadClient):
client.get("/api/products", headers={"Authorization": f"Bearer {self.token}"})
def check_browse(self, status_code: int, body) -> None:
assert status_code == 200
assert isinstance(body, list)
@task(weight=1)
def purchase(self, client: LoadClient):
client.post("/api/orders", json={"product_id": 42, "qty": 1},
headers={"Authorization": f"Bearer {self.token}"})
on_start— runs once per virtual user before tasks start (login, setup)@task— weighted HTTP task; multiple tasks run in proportioncheck_{task}— assertion after each request; fail = error counted
Features
| Python DSL | @scenario, @task, on_start, check_* — no new syntax to learn |
| Load profiles | ramp (default), constant, step, spike |
| SLA thresholds | fail CI with exit code 1 on p99/p95/error-rate breach |
| Distributed mode | coordinator + N agents over NATS; local or remote, free |
| HTML report | self-contained, open in any browser, no server required |
| Prometheus metrics | live Grafana dashboards while the test runs |
| Interactive TUI | loadpilot run with no args opens a scenario browser |
pip install |
coordinator binary bundled in the wheel, no Rust needed |
Performance
LoadPilot is benchmarked against k6 and Locust against a Rust/axum echo server in Docker.
LoadPilot runs in PyO3 mode — with on_start (login) and check_* (assertion per task) — a realistic workload with Python callbacks active.
Precision — 500 RPS target
| Tool | RPS actual | p50 | p99 | Errors | CPU avg |
|---|---|---|---|---|---|
| LoadPilot (PyO3) | 478 | 4ms | 15ms | 0% | 14% |
| k6 | 491 | 8ms | 118ms | 0% | 129% |
| Locust | 498 | 150ms | 1500ms | 0% | 88% |
LoadPilot uses 9× less CPU than k6 at the same load. Locust reaches the RPS target but its Python/GIL scheduler adds significant latency (p99 ≥ 1500ms at only 500 RPS).
Max throughput — 30s, no cap
| Tool | RPS | p50 | p99 | Errors | CPU avg |
|---|---|---|---|---|---|
| LoadPilot (PyO3) | 2205 | 11ms | 38ms | 0% | 165% |
| k6 | 1799 | 14ms | 175ms | 0% | 212% |
| Locust | 677 | 100ms | 170ms | 0% | 117% |
1.2× k6 and 3.3× Locust at max throughput. 1.6× better CPU efficiency per request vs k6.
→ Full benchmark details and methodology
SLA Thresholds
@scenario(
rps=100, duration="2m",
thresholds={"p99_ms": 500, "p95_ms": 300, "error_rate": 1.0},
)
class CheckoutFlow(VUser): ...
Thresholds
✓ p99 latency 41ms < 500ms
✓ p95 latency 28ms < 300ms
✓ error rate 0% < 1%
All thresholds passed.
Exit code 1 on breach — drop into any CI pipeline. Override without editing the file:
loadpilot run scenarios/checkout.py --target https://staging.example.com \
--threshold p99_ms=800 --threshold error_rate=2
Distributed Mode
# 4 local processes
loadpilot run scenarios/checkout.py --target https://api.example.com --agents 4
# external agents on remote machines
loadpilot run scenarios/checkout.py \
--target https://api.example.com \
--external-agents 4
The CLI output is identical to single-machine mode — the coordinator aggregates
everything transparently. on_start (login, setup) runs on the coordinator and
ships per-user auth headers to agents, so distributed tests can authenticate
without Python running on each agent.
Live Monitoring
# scaffolded by `loadpilot init`
docker compose -f monitoring/docker-compose.yml up -d
# Grafana → http://localhost:3000 (LoadPilot dashboard auto-imported)
# Prometheus → http://localhost:9091
Use Grafana to correlate load test metrics with your service's own metrics (CPU, DB latency, error rates) on the same timeline.
Development
Requires just.
just test # run all tests (Python + Rust)
just test-py # Python tests only
just test-rust # Rust tests only
just fix # auto-fix lint + format
just check # lint + format check (no writes, same as CI)
just build # cargo build (debug)
just build-release # cargo build --release
Documentation
- Getting Started
- DSL Reference —
@scenario,@task,on_start,check_*,client.batch() - CLI Reference — all flags for
loadpilot runandloadpilot init - Distributed Mode — local agents, remote agents, Railway, NATS
- Benchmark — methodology, full results, how to reproduce
- Architecture — how the Python DSL and Rust engine interact
- Development — building from source, running tests
License
MIT
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file loadpilot-0.2.0.tar.gz.
File metadata
- Download URL: loadpilot-0.2.0.tar.gz
- Upload date:
- Size: 90.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
457189a8e25ed1d3819c742dd2e91475585309f7301871eb31465bc147b6c577
|
|
| MD5 |
6f05b0dca97932bf5cdcb5edd46c8e25
|
|
| BLAKE2b-256 |
e9b98164be0da370b1943dcf1dd8feb50aa5c608bb3043ca09f47803ff8831b3
|
Provenance
The following attestation bundles were made for loadpilot-0.2.0.tar.gz:
Publisher:
release.yml on VladislavAkulich/loadpilot
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
loadpilot-0.2.0.tar.gz -
Subject digest:
457189a8e25ed1d3819c742dd2e91475585309f7301871eb31465bc147b6c577 - Sigstore transparency entry: 1189467898
- Sigstore integration time:
-
Permalink:
VladislavAkulich/loadpilot@254e4ae3c4fe787bd775a64c958e8625004d9f75 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/VladislavAkulich
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@254e4ae3c4fe787bd775a64c958e8625004d9f75 -
Trigger Event:
push
-
Statement type:
File details
Details for the file loadpilot-0.2.0-cp312-cp312-win_amd64.whl.
File metadata
- Download URL: loadpilot-0.2.0-cp312-cp312-win_amd64.whl
- Upload date:
- Size: 4.0 MB
- Tags: CPython 3.12, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f9bc3ce4837176ced4f52bb2066f013066b166731879c571be0053818628b7e2
|
|
| MD5 |
03c04aeaf9ecc78deefef60af649aa5b
|
|
| BLAKE2b-256 |
7c0bebe145358be681129e19760f24069c2f0c472620dfb49d5157931e486a6c
|
Provenance
The following attestation bundles were made for loadpilot-0.2.0-cp312-cp312-win_amd64.whl:
Publisher:
release.yml on VladislavAkulich/loadpilot
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
loadpilot-0.2.0-cp312-cp312-win_amd64.whl -
Subject digest:
f9bc3ce4837176ced4f52bb2066f013066b166731879c571be0053818628b7e2 - Sigstore transparency entry: 1189467905
- Sigstore integration time:
-
Permalink:
VladislavAkulich/loadpilot@254e4ae3c4fe787bd775a64c958e8625004d9f75 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/VladislavAkulich
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@254e4ae3c4fe787bd775a64c958e8625004d9f75 -
Trigger Event:
push
-
Statement type:
File details
Details for the file loadpilot-0.2.0-cp312-cp312-manylinux_2_38_x86_64.whl.
File metadata
- Download URL: loadpilot-0.2.0-cp312-cp312-manylinux_2_38_x86_64.whl
- Upload date:
- Size: 4.1 MB
- Tags: CPython 3.12, manylinux: glibc 2.38+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f1fb20bcd2e39aa708b9db858a44f3756332225ddde8f12f8c5fca9d0706bb20
|
|
| MD5 |
2320f9004cd9e967c6742eb3e8aa8b7a
|
|
| BLAKE2b-256 |
57136880aaa094dc87c1255b75ba768f464120909bfb0f97404397e0a13861d1
|
Provenance
The following attestation bundles were made for loadpilot-0.2.0-cp312-cp312-manylinux_2_38_x86_64.whl:
Publisher:
release.yml on VladislavAkulich/loadpilot
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
loadpilot-0.2.0-cp312-cp312-manylinux_2_38_x86_64.whl -
Subject digest:
f1fb20bcd2e39aa708b9db858a44f3756332225ddde8f12f8c5fca9d0706bb20 - Sigstore transparency entry: 1189467913
- Sigstore integration time:
-
Permalink:
VladislavAkulich/loadpilot@254e4ae3c4fe787bd775a64c958e8625004d9f75 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/VladislavAkulich
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@254e4ae3c4fe787bd775a64c958e8625004d9f75 -
Trigger Event:
push
-
Statement type:
File details
Details for the file loadpilot-0.2.0-cp312-cp312-macosx_11_0_arm64.whl.
File metadata
- Download URL: loadpilot-0.2.0-cp312-cp312-macosx_11_0_arm64.whl
- Upload date:
- Size: 4.3 MB
- Tags: CPython 3.12, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
34fa37e5cbc6441f1e26ef590da874950d80da840ebe997272390c3ea30309b3
|
|
| MD5 |
7293b31b85cfbaf0ee6c2bd9674471dd
|
|
| BLAKE2b-256 |
2f45210700f85b0d5abaf88a43cca752825a652a59162c9581c36ca8baba4a92
|
Provenance
The following attestation bundles were made for loadpilot-0.2.0-cp312-cp312-macosx_11_0_arm64.whl:
Publisher:
release.yml on VladislavAkulich/loadpilot
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
loadpilot-0.2.0-cp312-cp312-macosx_11_0_arm64.whl -
Subject digest:
34fa37e5cbc6441f1e26ef590da874950d80da840ebe997272390c3ea30309b3 - Sigstore transparency entry: 1189467910
- Sigstore integration time:
-
Permalink:
VladislavAkulich/loadpilot@254e4ae3c4fe787bd775a64c958e8625004d9f75 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/VladislavAkulich
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@254e4ae3c4fe787bd775a64c958e8625004d9f75 -
Trigger Event:
push
-
Statement type: