diff --git a/TODO.md b/TODO.md index cca4918..29b9e2e 100644 --- a/TODO.md +++ b/TODO.md @@ -31,6 +31,21 @@ P2: security: per-IP rate limiting on the image routes # Completed Steps +- 2026-10-04 load test (closes #81): `script/loadtest [duration [clients]]` + (`make loadtest`, defaults `10s` and `4`), a benchmark that `script/check` + does not run, measures three scenarios, each against a new pixad container and + a new upstream host, `cmd/loadtest-origin`: `hit` (one cached image), `miss` + (a new source image every request) and `herd` (each new source image asked for + by all clients at once). For each it prints vegeta's report (requests per + second, latency percentiles, status codes), pixad's peak resident memory and + the requests that reached the origin. `README.md` says how to run it and read + it, and keeps 1-5k r/s as a target not yet measured. First measurement, with + the defaults on a shared 48-CPU machine with other work running: a baseline + for later changes, not a test of the target. `hit` 1413 r/s, p50 0.7 ms, p95 + 8.7 ms, p99 44 ms, peak 53 MiB (4 clients that each wait for their answer, so + not pixad's limit); `miss` 70 r/s, p50 52 ms, p95 91 ms, p99 122 ms, peak 100 + MiB, one fetch per request; `herd` 74 r/s, p50 52 ms, p95 69 ms, p99 111 ms, + peak 60 MiB, 188 fetches for 749 requests. - 2026-10-04 the CI checkout fetches the tags (closes #208): the checkout step in `.gitea/workflows/check.yml` sets `fetch-depth: 0`, as `REPO_POLICIES.md` asks of a repo that takes its version from the tags, so a CI build of a tagged @@ -56,30 +71,6 @@ P2: security: per-IP rate limiting on the image routes comment are copied from the canonical `.gitignore` in `sneak/prompts`, unanchored so it matches at every depth. `.dockerignore` already has `.claude`. -- 2026-10-04 load test (closes #81): `script/loadtest [duration [clients]]` - (`make loadtest`, defaults `10s` and `4`), a benchmark that `script/check` - does not run, measures three scenarios, each against a new pixad container and - a new upstream host, `cmd/loadtest-origin`: `hit` (one cached image), `miss` - (a new source image every request) and `herd` (each new source image asked for - by all clients at once). For each it prints vegeta's report (requests per - second, latency percentiles, status codes), pixad's peak resident memory and - the requests that reached the origin. `README.md` says how to run it and read - it, and keeps 1-5k r/s as a target not yet measured. First measurement, with - the defaults on a shared 48-CPU machine with other work running: a baseline - for later changes, not a test of the target. `hit` 1413 r/s, p50 0.7 ms, p95 - 8.7 ms, p99 44 ms, peak 53 MiB (4 clients that each wait for their answer, so - not pixad's limit); `miss` 70 r/s, p50 52 ms, p95 91 ms, p99 122 ms, peak 100 - MiB, one fetch per request; `herd` 74 r/s, p50 52 ms, p95 69 ms, p99 111 ms, - peak 60 MiB, 188 fetches for 749 requests. -- 2026-10-04 `cmd/pixad/main.go` is one call into `internal/` (closes #206): - what it did (the command line and its `--config` flag, setting - `PIXA_CONFIG_PATH`, ignoring `SIGPIPE`, starting the fx app) is now `Run` in - `internal/app`, unchanged, and `main` calls it with `Version`, which the build - still sets through `-X main.Version`. That code had no tests to move. -- 2026-10-04 `.gitignore` ignores `.claude/` (closes #204): the entry and its - comment are copied from the canonical `.gitignore` in `sneak/prompts`, - unanchored so it matches at every depth. `.dockerignore` already has - `.claude`. - 2026-10-04 `.dockerignore` keeps secrets out at every depth (closes #205): the file is now the standard one from `sneak/prompts`, whose patterns match in every directory and, for environment files and private keys, in any letter diff --git a/script/loadtest b/script/loadtest index 885b283..bcc361e 100755 --- a/script/loadtest +++ b/script/loadtest @@ -51,8 +51,10 @@ main() { "" | *[!0-9]*) usage ;; esac [ "$number" -gt 0 ] || usage + # The number of clients is a whole number that does not start with 0, + # which also refuses zero: vegeta reads a leading 0 as octal. case "$clients" in - *[!0-9]* | 0) usage ;; + *[!0-9]* | 0*) usage ;; esac cd "$ROOT"