markdown · 2810 bytes Raw Blame History

Load tests

k6 scenarios used in the S39 hardening sprint. Each script is a single load shape; combine them by running concurrently from a load-generator host (the staging instance must NOT receive load from the production droplet).

Scenarios

Script Shape
scenarios/mixed-read.js 100 RPS anonymous browsing of public repos for 10 min
scenarios/auth-mix.js 50 RPS authenticated API + browsing for 10 min
scenarios/issue-comment-storm.js 100 comments/sec across 50 issues for 5 min
scenarios/search-load.js 30 RPS to search endpoints for 10 min

Two scenarios from the S39 spec are not yet shipped here:

  • Push storm — needs a Git client harness, not k6's HTTP runner. Track in a follow-up.
  • SSH connection burst — needs a real SSH client; the SSH transport itself isn't shipped (see docs/public/user/ssh.md). When SSH lands, add an SSH-specific scenario.

Running locally against the dev server

make dev-db dev-storage dev-migrate dev
# in another terminal:
make load-test BENCH_TARGET=http://127.0.0.1:8080

make load-test runs the mixed-read scenario by default; tune with K6_SCENARIO=auth-mix make load-test etc.

Running against staging

export BASE=https://staging.shithub.sh
export TOKEN=shp_<a-pat-on-a-test-account>
export REPO=loadtest/issue-storm  # for the comment-storm scenario
export FIRST_ISSUE=1

k6 run -e BASE -e TOKEN tests/load/k6/scenarios/auth-mix.js
k6 run -e BASE                     tests/load/k6/scenarios/mixed-read.js
k6 run -e BASE -e TOKEN -e REPO -e FIRST_ISSUE tests/load/k6/scenarios/issue-comment-storm.js
k6 run -e BASE                     tests/load/k6/scenarios/search-load.js

Thresholds

thresholds.json is shared across scenarios. Default thresholds:

  • HTTP failure rate < 1% (excluding rate-limit 429s, which k6 doesn't classify as failures).
  • p95 < 3000 ms.
  • p99 < 5000 ms.
  • Per-check pass rate > 99%.

These come from the S39 spec: "p95 < 2x of S36's single-user bench numbers under sustained load." Tighten them once production has run for a quarter.

What good looks like

After a clean run, capture the JSON output:

k6 run --out json=results.json tests/load/k6/scenarios/mixed-read.js

Summarise per-scenario p50/p95/p99 + total RPS into the capacity record (docs/internal/capacity.md). The numbers there are "S39 baseline at MVP launch"; subsequent hardening sprints diff against them to catch regressions.

View source
1 # Load tests
2
3 k6 scenarios used in the S39 hardening sprint. Each script is a
4 single load shape; combine them by running concurrently from a
5 load-generator host (the staging instance must NOT receive load
6 from the production droplet).
7
8 ## Scenarios
9
10 | Script | Shape |
11 |-------------------------------------|-----------------------------------------------------------------------|
12 | `scenarios/mixed-read.js` | 100 RPS anonymous browsing of public repos for 10 min |
13 | `scenarios/auth-mix.js` | 50 RPS authenticated API + browsing for 10 min |
14 | `scenarios/issue-comment-storm.js` | 100 comments/sec across 50 issues for 5 min |
15 | `scenarios/search-load.js` | 30 RPS to search endpoints for 10 min |
16
17 Two scenarios from the S39 spec are not yet shipped here:
18
19 - **Push storm** — needs a Git client harness, not k6's HTTP runner.
20 Track in a follow-up.
21 - **SSH connection burst** — needs a real SSH client; the SSH
22 transport itself isn't shipped (see
23 `docs/public/user/ssh.md`). When SSH lands, add an SSH-specific
24 scenario.
25
26 ## Running locally against the dev server
27
28 ```sh
29 make dev-db dev-storage dev-migrate dev
30 # in another terminal:
31 make load-test BENCH_TARGET=http://127.0.0.1:8080
32 ```
33
34 `make load-test` runs the mixed-read scenario by default; tune
35 with `K6_SCENARIO=auth-mix make load-test` etc.
36
37 ## Running against staging
38
39 ```sh
40 export BASE=https://staging.shithub.sh
41 export TOKEN=shp_<a-pat-on-a-test-account>
42 export REPO=loadtest/issue-storm # for the comment-storm scenario
43 export FIRST_ISSUE=1
44
45 k6 run -e BASE -e TOKEN tests/load/k6/scenarios/auth-mix.js
46 k6 run -e BASE tests/load/k6/scenarios/mixed-read.js
47 k6 run -e BASE -e TOKEN -e REPO -e FIRST_ISSUE tests/load/k6/scenarios/issue-comment-storm.js
48 k6 run -e BASE tests/load/k6/scenarios/search-load.js
49 ```
50
51 ## Thresholds
52
53 `thresholds.json` is shared across scenarios. Default thresholds:
54
55 - HTTP failure rate < 1% (excluding rate-limit 429s, which k6
56 doesn't classify as failures).
57 - p95 < 3000 ms.
58 - p99 < 5000 ms.
59 - Per-check pass rate > 99%.
60
61 These come from the S39 spec: "p95 < 2x of S36's single-user
62 bench numbers under sustained load." Tighten them once
63 production has run for a quarter.
64
65 ## What good looks like
66
67 After a clean run, capture the JSON output:
68
69 ```sh
70 k6 run --out json=results.json tests/load/k6/scenarios/mixed-read.js
71 ```
72
73 Summarise per-scenario p50/p95/p99 + total RPS into the capacity
74 record (`docs/internal/capacity.md`). The numbers there are
75 "S39 baseline at MVP launch"; subsequent hardening sprints diff
76 against them to catch regressions.