Chapter 18 · CI/CD Integration
Chapter goals: Embed Locust load tests into GitHub Actions pipelines, implement headless automatic execution, performance threshold judgments, result archiving, and scheduled load testing.
18.1 Headless Mode Execution
CI environments have no GUI. Locust provides --headless to skip the Web UI and run directly:
# Basic usage: 10 users, 2 spawned per second, 60 seconds duration
locust -f locustfile.py --headless \
--users 10 \
--spawn-rate 2 \
--run-time 60s \
--host https://staging.example.comKey parameters:
| Parameter | Short | Description |
|---|---|---|
--headless | — | Do not start the Web UI |
--users / -u | -u | Target concurrent users |
--spawn-rate / -r | -r | User spawn rate (users/second) |
--run-time / -t | -t | Test duration (e.g., 60s, 5m) |
--host | -H | Base URL of the system under test |
Exit code mechanism
Locust exits with a non-zero code when there are request failures. Combined with the events.quitting listener from Chapter 16 that sets process_exit_code = 1, CI can correctly mark the build as failed when failure rate or p95 exceeds thresholds.
18.2 GitHub Actions Workflow
Complete GitHub Actions configuration example:
# .github/workflows/load-test.yml
name: Performance Test
on:
workflow_dispatch: # Manual trigger
inputs:
target_url:
description: 'Target URL'
required: true
default: 'https://staging.example.com'
user_count:
description: 'Concurrent users'
required: false
default: '50'
schedule:
- cron: '0 6 * * 1' # Every Monday 6:00 UTC
jobs:
load-test:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install dependencies
run: pip install locust
- name: Run load test
id: locust
run: |
locust -f locustfile.py --headless \
--users ${{ github.event.inputs.user_count || '50' }} \
--spawn-rate 10 \
--run-time 120s \
--host ${{ github.event.inputs.target_url }} \
--csv results/perf_report \
--html results/report.html \
--only-summary
- name: Upload artifacts
uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: locust-results-${{ github.run_id }}
path: results/18.3 Adding Performance Threshold Gates
Define pass/fail criteria using the events.quitting hook:
# locustfile.py
from locust import events
@events.quitting.add_listener
def check_thresholds(environment, **kwargs):
stats = environment.runner.stats
# Fail if failure rate > 1%
if stats.total.num_failures / max(stats.total.num_requests, 1) > 0.01:
environment.process_exit_code = 1
print("FAIL: failure rate exceeds 1%")
# Fail if p95 > 500ms
p95 = stats.total.avg_response_time # Note: use proper percentile calc
if p95 > 500:
environment.process_exit_code = 1
print(f"FAIL: p95 response time {p95}ms exceeds 500ms")When process_exit_code = 1, the CI step fails and the pipeline blocks merge.
18.4 Chapter Summary
--headless+ CLI flags replace the Web UI for CI;- GitHub Actions: checkout → setup Python → install locust → run headless → upload artifacts;
events.quittinghook setsprocess_exit_code = 1on threshold breach to block CI;- Schedule with
cronfor nightly regression load tests.
🧪 随堂测验
点击你认为正确的选项。答错时会展示正确答案与原因解析。
1. What flag makes Locust suitable for CI pipelines?
2. How do you make a CI pipeline fail when p95 exceeds a threshold?
3. What is the purpose of --only-summary in headless mode?
4. How do you schedule a nightly load test in GitHub Actions?
🛠️ Hands-On Exercises
- Write a GitHub Actions workflow that runs a headless Locust test on every push to main; upload CSV and HTML artifacts.
- Add a
events.quittinglistener that fails the build if p95 > 500ms or failure rate > 1%. - Add a
schedule: cron: '0 6 * * 1'trigger for weekly regression; verify it runs automatically.
Proceed to Chapter 19: Monitoring and Results Analysis.