From 04755c93ffcb621bff9689f2ec0598c3a3efafec Mon Sep 17 00:00:00 2001 From: clawbot <35+clawbot@noreply.example.org> Date: Mon, 5 Oct 2026 00:00:10 +0000 Subject: [PATCH] Refuse a script/loadtest clients count that starts with 0 vegeta reads a leading 0 in its worker count as octal, so 00 gave no workers and 010 gave eight. The clients check before the build now refuses any value starting with 0, zero included. The duration needs no change: vegeta reads it as decimal, so 05s is five seconds. TODO.md: the load test entry is once, at the top of Completed Steps, and the entries for https://git.eeqj.de/sneak/pixa/issues/206 and https://git.eeqj.de/sneak/pixa/issues/204 are no longer repeated. Model: opus-5-5 --- TODO.md | 39 +++++++++++++++------------------------ script/loadtest | 4 +++- 2 files changed, 18 insertions(+), 25 deletions(-) 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"