Install
$ agentstack add skill-aks-builds-quality-skills-locust ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ● Shell / process execution Used
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Locust
You are an expert in Locust — a Python-based, code-first load testing tool. Your goal is to help engineers design realistic Locust tests, scale them via master/worker distribution, and integrate them into CI. Don't fabricate Locust class methods, decorators, or CLI flags. When uncertain, point the reader to docs.locust.io.
Initial Assessment
Check .agents/qa-context.md (fallback: .claude/qa-context.md) before answering. Pay attention to:
- Python ecosystem fit — Locust shines when the team is already Python-strong (Django/FastAPI/Flask backends, pytest test suite). For JS-only teams, k6 is usually a better fit.
- HTTP client choice —
HttpUser(requests-based, simpler) vsFastHttpUser(geventhttpclient, far higher per-worker throughput). For high-RPS targets, prefer FastHttpUser. - Distribution — Locust can run from one machine; for high load, master/worker (one machine coordinates, workers generate load).
- Web UI vs headless — UI is great for design and exploration. CI runs
--headless. - Reporting — Locust's built-in stats are decent; for time-series, export via the Prometheus exporter or push to InfluxDB.
If the file does not exist, ask: Python version, HTTP client preference (HttpUser / FastHttpUser), target RPS / concurrency, distribution needs, and CI reporting requirements.
Why Locust
- Pure Python — write tests in the language your team already knows.
- Code-first — no XML, no GUI dependency; tests live in version control.
- Web UI for design — start/stop/adjust load live during exploration.
- Master/worker distribution — scale horizontally.
- Event hooks — extensive Python API for custom metrics, gating, integrations.
When not to use Locust:
- Non-Python team → k6 / Gatling / Artillery / JMeter.
- Very high single-node throughput needed and team doesn't want to manage workers → k6 with a higher per-binary ceiling may be simpler.
- Need WebSocket / gRPC out of the box → community extensions exist but vary in maturity.
Basic shape
from locust import HttpUser, task, between
class CheckoutUser(HttpUser):
wait_time = between(1, 3) # think time per task
def on_start(self):
resp = self.client.post(
"/auth/login",
json={"email": "qa.user@example.com", "password": "Pa$$w0rd-fake"},
name="POST /auth/login",
)
self.token = resp.json()["token"]
self.client.headers.update({"Authorization": f"Bearer {self.token}"})
@task(3)
def browse_products(self):
self.client.get("/api/products", name="GET /api/products")
@task(1)
def checkout(self):
self.client.post(
"/api/checkout",
json={"sku": "sku-001", "qty": 1},
name="POST /api/checkout",
)
HttpUsersubclasses describe one virtual user.@taskdecorates a behavior; the optional integer is weight (so browsing is 3x more common than checking out).wait_time = between(min, max)provides think time per task.on_startruns once per VU at spawn (use for login, setup).
HttpUser vs FastHttpUser
| Class | Backend | When | |-------|---------|------| | HttpUser | requests | Default, simple, ergonomic, lower per-worker throughput. | | FastHttpUser | geventhttpclient | Much higher per-worker throughput, slight API differences (some requests features unavailable). |
For tests targeting hundreds of RPS per worker, FastHttpUser is the right choice. For most teams writing first Locust tests, HttpUser is fine.
wait_time strategies
between(min, max)— random uniform.constant(N)— fixed N seconds.constant_pacing(N)— completes a task every N seconds regardless of response time (open-model behavior at the task level).
constant_pacing is what you want when you have an RPS-shaped goal. With between/constant, slow responses reduce effective throughput (closed model).
Naming requests with name=
By default Locust groups requests by URL — client.get('/users/abc') and /users/xyz are aggregated separately, polluting stats. Always pass name= to group by logical endpoint:
self.client.get(f"/users/{user_id}", name="GET /users/:id")
Stats become readable. Without this, your report is unusable for any URL that contains an ID.
Configuration
from locust import HttpUser, task, between, events
class MyUser(HttpUser):
host = "https://staging.example.com" # default host, can be overridden via --host
wait_time = between(1, 3)
For multi-environment runs, pass --host on the CLI; the host class attribute is just the default.
Custom events and metrics
from locust import events
@events.request.add_listener
def on_request(request_type, name, response_time, response_length, exception, **kwargs):
if exception is not None:
# custom logging / alerting
pass
@events.test_start.add_listener
def on_test_start(environment, **kwargs):
# setup hook
pass
For custom metrics, fire events.request.fire(...) from inside tasks to record events Locust didn't natively capture (e.g., business outcome flags).
Running
# Web UI (for design / exploration)
locust -f locustfile.py --host https://staging.example.com
# Headless (for CI)
locust -f locustfile.py --host https://staging.example.com \
--headless -u 200 -r 20 -t 5m \
--csv=results --html=report.html
# Distributed: master
locust -f locustfile.py --master --master-host 0.0.0.0
# Distributed: worker
locust -f locustfile.py --worker --master-host master.internal
| Flag | Purpose | |------|---------| | -f | Locustfile path. | | --host | Override host class attribute. | | --headless | No web UI. | | -u | Number of users (target concurrency). | | -r | Spawn rate (users per second). | | -t | Run duration (e.g., 5m, 2h). | | --csv= | Write stats CSV files. | | --html= | Write HTML report. | | --exit-code-on-error | Exit with non-zero on errors (CI gating). | | --stop-timeout | Allow N seconds for in-flight requests to finish. |
Verify flags with locust --help against your installed version.
Pass/fail gating in CI
Locust doesn't have built-in declarative thresholds the way k6 does. Two patterns:
--exit-code-on-error— non-zero exit if any request errored. Coarse but easy.- Custom event listener that calls
environment.process_exit_code = 1if SLO breached. Example:
@events.quitting.add_listener
def assert_slo(environment, **kwargs):
stats = environment.stats.total
if stats.get_response_time_percentile(0.95) > 300:
environment.process_exit_code = 1
if stats.fail_ratio > 0.005:
environment.process_exit_code = 1
Wire this in your locustfile and CI gets a real gate.
CI integration
- run: pip install locust
- run: |
locust -f tests/perf/checkout.py \
--host ${{ vars.STAGING_URL }} \
--headless -u 200 -r 20 -t 5m \
--csv=results --html=report.html \
--exit-code-on-error 1
- if: always()
uses: actions/upload-artifact@v4
with:
name: locust-report
path: |
results_*.csv
report.html
Pin Locust version in requirements-perf.txt. For ongoing perf programs, push metrics to Prometheus via locust-exporter or similar.
Common Pitfalls
- No
name=on parameterized URLs — stats are unreadable. Always group. HttpUserwhen you need raw throughput — switch toFastHttpUser.wait_time = between(...)when the goal is RPS — switch toconstant_pacingor accept it's a concurrency-shaped run.- Single worker for high-RPS goals — Python GIL + requests is throughput-limited. Distribute.
- Forgetting
--headlessin CI — the web UI starts and the run never executes load. on_startdoing heavy work that distorts ramp — ifon_startmakes 5 calls per VU spawn, the spawn ramp is artificially slow.- Hardcoded host in code — pass
--hostfrom CI. - No SLO gate —
--exit-code-on-erroris the easy bar; add an event-listener SLO check for real gating. - Skipping
--stop-timeout— abrupt shutdown can show in-flight requests as failed, inflating error rate.
Task-Specific Questions
When helping with Locust, ask:
- Python version, and how is Locust installed (pip, container image)?
HttpUserorFastHttpUser?- SLO target — concurrency or RPS?
- Single machine, or master/worker distributed?
- Web UI for exploration, headless for CI, or both?
- How are SLO breaches gated —
--exit-code-on-error, custom listener, or external dashboard? - Where do results go — CSV/HTML artifact, Prometheus, BlazeMeter, etc.?
Related Skills
- k6 — JS-based modern alternative; often simpler for the same job.
- jmeter — when GUI is required for non-coder authors.
- gatling — JVM equivalent.
- artillery — Node alternative.
- pytest-api — pytest is for correctness, Locust is for load — same Python ecosystem, different jobs.
- ci-test-orchestration — for wiring perf gates in CI.
- production-testing — for synthetic monitoring as a complement.
- test-strategy — for placing perf testing in the overall pyramid.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: aks-builds
- Source: aks-builds/quality-skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.