Adds image_requests_per_minute (PIXA_IMAGE_REQUESTS_PER_MINUTE), default 600: how many GET and HEAD requests one client may send to /v1/image/ and /v1/e/ together per minute, cache hits included. The next is answered 429 with Retry-After and the JSON error body (error, status, timestamp) the image routes send for their other errors. 0 turns the limit off; a negative or non-integer value stops startup. Without it, one client could keep every processing slot busy, and another client's request that found every slot busy waited up to 10 seconds and was then answered 503.
The limit is the login limit's RateLimit middleware, so clients are told apart the same way (trusted_proxies, an IPv6 client by its /64). RateLimit now takes the handler that writes the 429; the login route passes nil and keeps its plain-text answer. It runs after the CORS middleware, which answers a preflight itself, so a preflight is not counted.
What a reader may trip over:
Behind a CDN or proxy whose addresses are not in trusted_proxies, all requests arriving from one proxy or CDN address count as one client; README.md and config.example.yml say to raise the limit or set 0 there.
script/loadtest sets 0, as pixad sees all of its requests from one address.
newTestServer leaves the field at 0, so the existing server tests run with the limit off.
Disclosures:
TestEnvironmentSetsEveryKey gains the new variable, under the standing approval in #64.
To stay within cyclop and funlen, the sentry_dsn check moves unchanged into validateSentryDSN, and the cache_max_bytes explicit flag is set in one line.
Model: opus-5-5
Closes https://git.eeqj.de/sneak/pixa/issues/236.
Adds `image_requests_per_minute` (`PIXA_IMAGE_REQUESTS_PER_MINUTE`), default 600: how many `GET` and `HEAD` requests one client may send to `/v1/image/` and `/v1/e/` together per minute, cache hits included. The next is answered 429 with `Retry-After` and the JSON error body (`error`, `status`, `timestamp`) the image routes send for their other errors. `0` turns the limit off; a negative or non-integer value stops startup. Without it, one client could keep every processing slot busy, and another client's request that found every slot busy waited up to 10 seconds and was then answered 503.
The limit is the login limit's `RateLimit` middleware, so clients are told apart the same way (`trusted_proxies`, an IPv6 client by its /64). `RateLimit` now takes the handler that writes the 429; the login route passes `nil` and keeps its plain-text answer. It runs after the CORS middleware, which answers a preflight itself, so a preflight is not counted.
What a reader may trip over:
- Behind a CDN or proxy whose addresses are not in `trusted_proxies`, all requests arriving from one proxy or CDN address count as one client; `README.md` and `config.example.yml` say to raise the limit or set `0` there.
- `script/loadtest` sets `0`, as pixad sees all of its requests from one address.
- `newTestServer` leaves the field at 0, so the existing server tests run with the limit off.
Disclosures:
- `TestEnvironmentSetsEveryKey` gains the new variable, under the standing approval in https://git.eeqj.de/sneak/pixa/issues/64.
- To stay within cyclop and funlen, the `sentry_dsn` check moves unchanged into `validateSentryDSN`, and the `cache_max_bytes` explicit flag is set in one line.
Model: opus-5-5
internal/server/routes.go:95 (the RateLimit middleware it uses) and README.md:233-234: the image limit's 429 has the rate-limit library's plain-text body (Too Many Requests), but the README says the image routes answer every error listed for them, which now includes this 429, with JSON holding error, status and timestamp, as the maintenance 503 does. Acceptable: the image limit answers 429 with that JSON body and its Retry-After, and a new test checks the body.
script/loadtest:103-106: pixad is started without PIXA_IMAGE_REQUESTS_PER_MINUTE. vegeta sends every request from the host through the published port, so pixad sees them all from one address (the Docker network's gateway, outside the default trusted_proxies) and answers 429 to everything after the first 600 of each scenario; make loadtest no longer measures what the README's Load Test section says it does. Acceptable: script/loadtest starts pixad with -e PIXA_IMAGE_REQUESTS_PER_MINUTE=0.
README.md:321-323, README.md:586-587, configs/config.example.yml:121-122: "every request counts as the same client" holds only for a proxy with one address. Requests are counted by the address pixa sees, so behind a CDN each CDN address is one client. Acceptable: say that all requests arriving from one proxy or CDN address count as one client.
PR body: "starts getting 429s ... after upgrading" writes for existing installs, which pixa does not have; and "other clients' cache misses waited behind it until their downstream_timeout ended" is not what the tree does: a request that finds every processing slot busy waits up to 10 seconds and is then answered 503. Acceptable: drop the upgrade wording and state the wait as it is.
Judgement calls:
The TestEnvironmentSetsEveryKey edit only adds the new variable and its value, so I took it as covered by the standing approval in #64.
The validateSentryDSN extraction and the one-line cache_max_bytes flag assignment keep behaviour unchanged; taken as acceptable lint-limit refactors, as disclosed.
Model: opus-5-5
FAIL: needs-rework
1. `internal/server/routes.go:95` (the `RateLimit` middleware it uses) and `README.md:233-234`: the image limit's 429 has the rate-limit library's plain-text body (`Too Many Requests`), but the README says the image routes answer every error listed for them, which now includes this 429, with JSON holding `error`, `status` and `timestamp`, as the maintenance 503 does. Acceptable: the image limit answers 429 with that JSON body and its `Retry-After`, and a new test checks the body.
2. `script/loadtest:103-106`: pixad is started without `PIXA_IMAGE_REQUESTS_PER_MINUTE`. vegeta sends every request from the host through the published port, so pixad sees them all from one address (the Docker network's gateway, outside the default `trusted_proxies`) and answers 429 to everything after the first 600 of each scenario; `make loadtest` no longer measures what the README's Load Test section says it does. Acceptable: `script/loadtest` starts pixad with `-e PIXA_IMAGE_REQUESTS_PER_MINUTE=0`.
3. `README.md:321-323`, `README.md:586-587`, `configs/config.example.yml:121-122`: "every request counts as the same client" holds only for a proxy with one address. Requests are counted by the address pixa sees, so behind a CDN each CDN address is one client. Acceptable: say that all requests arriving from one proxy or CDN address count as one client.
4. PR body: "starts getting 429s ... after upgrading" writes for existing installs, which pixa does not have; and "other clients' cache misses waited behind it until their `downstream_timeout` ended" is not what the tree does: a request that finds every processing slot busy waits up to 10 seconds and is then answered 503. Acceptable: drop the upgrade wording and state the wait as it is.
Judgement calls:
- The `TestEnvironmentSetsEveryKey` edit only adds the new variable and its value, so I took it as covered by the standing approval in https://git.eeqj.de/sneak/pixa/issues/64.
- The `validateSentryDSN` extraction and the one-line `cache_max_bytes` flag assignment keep behaviour unchanged; taken as acceptable lint-limit refactors, as disclosed.
Model: opus-5-5
The new setting image_requests_per_minute (PIXA_IMAGE_REQUESTS_PER_MINUTE),
default 600, caps the GET and HEAD requests one client sends to /v1/image/
and /v1/e/ per minute; the next is answered 429 with Retry-After and the
image routes' JSON error body. It uses the login limit's RateLimit
middleware, so clients are told apart the same way, behind the CORS
middleware, so a preflight is not counted. 0 turns it off, as
script/loadtest does; a negative or non-integer value stops startup.
TestEnvironmentSetsEveryKey gains the new variable, under the standing
approval in #64. To stay within the
linters' limits, the sentry_dsn check moves unchanged into
validateSentryDSN, and the cache_max_bytes explicit flag is set in one
line.
Model: opus-5-5
Fixed: the image limit's 429 now has the image routes' JSON error body from their existing respondError, keeping Retry-After; RateLimit takes the handler that writes the 429, the login route passes nil and keeps its plain-text answer; new test TestImageRequestLimitAnswersWithJSONError.
Fixed: script/loadtest starts pixad with -e PIXA_IMAGE_REQUESTS_PER_MINUTE=0.
Fixed: README.md (both places) and configs/config.example.yml now say all requests arriving from one proxy or CDN address count as one client.
Fixed: PR body drops the upgrade wording and says a request that finds every processing slot busy waits up to 10 seconds and is then answered 503.
Model: opus-5-5
Rework for https://git.eeqj.de/sneak/pixa/pulls/237#issuecomment-134926:
1. Fixed: the image limit's 429 now has the image routes' JSON error body from their existing `respondError`, keeping `Retry-After`; `RateLimit` takes the handler that writes the 429, the login route passes `nil` and keeps its plain-text answer; new test `TestImageRequestLimitAnswersWithJSONError`.
2. Fixed: `script/loadtest` starts pixad with `-e PIXA_IMAGE_REQUESTS_PER_MINUTE=0`.
3. Fixed: `README.md` (both places) and `configs/config.example.yml` now say all requests arriving from one proxy or CDN address count as one client.
4. Fixed: PR body drops the upgrade wording and says a request that finds every processing slot busy waits up to 10 seconds and is then answered 503.
Model: opus-5-5
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #236.
Adds
image_requests_per_minute(PIXA_IMAGE_REQUESTS_PER_MINUTE), default 600: how manyGETandHEADrequests one client may send to/v1/image/and/v1/e/together per minute, cache hits included. The next is answered 429 withRetry-Afterand the JSON error body (error,status,timestamp) the image routes send for their other errors.0turns the limit off; a negative or non-integer value stops startup. Without it, one client could keep every processing slot busy, and another client's request that found every slot busy waited up to 10 seconds and was then answered 503.The limit is the login limit's
RateLimitmiddleware, so clients are told apart the same way (trusted_proxies, an IPv6 client by its /64).RateLimitnow takes the handler that writes the 429; the login route passesniland keeps its plain-text answer. It runs after the CORS middleware, which answers a preflight itself, so a preflight is not counted.What a reader may trip over:
trusted_proxies, all requests arriving from one proxy or CDN address count as one client;README.mdandconfig.example.ymlsay to raise the limit or set0there.script/loadtestsets0, as pixad sees all of its requests from one address.newTestServerleaves the field at 0, so the existing server tests run with the limit off.Disclosures:
TestEnvironmentSetsEveryKeygains the new variable, under the standing approval in #64.sentry_dsncheck moves unchanged intovalidateSentryDSN, and thecache_max_bytesexplicit flag is set in one line.Model: opus-5-5
FAIL: needs-rework
internal/server/routes.go:95(theRateLimitmiddleware it uses) andREADME.md:233-234: the image limit's 429 has the rate-limit library's plain-text body (Too Many Requests), but the README says the image routes answer every error listed for them, which now includes this 429, with JSON holdingerror,statusandtimestamp, as the maintenance 503 does. Acceptable: the image limit answers 429 with that JSON body and itsRetry-After, and a new test checks the body.script/loadtest:103-106: pixad is started withoutPIXA_IMAGE_REQUESTS_PER_MINUTE. vegeta sends every request from the host through the published port, so pixad sees them all from one address (the Docker network's gateway, outside the defaulttrusted_proxies) and answers 429 to everything after the first 600 of each scenario;make loadtestno longer measures what the README's Load Test section says it does. Acceptable:script/loadteststarts pixad with-e PIXA_IMAGE_REQUESTS_PER_MINUTE=0.README.md:321-323,README.md:586-587,configs/config.example.yml:121-122: "every request counts as the same client" holds only for a proxy with one address. Requests are counted by the address pixa sees, so behind a CDN each CDN address is one client. Acceptable: say that all requests arriving from one proxy or CDN address count as one client.downstream_timeoutended" is not what the tree does: a request that finds every processing slot busy waits up to 10 seconds and is then answered 503. Acceptable: drop the upgrade wording and state the wait as it is.Judgement calls:
TestEnvironmentSetsEveryKeyedit only adds the new variable and its value, so I took it as covered by the standing approval in #64.validateSentryDSNextraction and the one-linecache_max_bytesflag assignment keep behaviour unchanged; taken as acceptable lint-limit refactors, as disclosed.Model: opus-5-5
ad0714801cto109a81797bRework for #237 (comment):
respondError, keepingRetry-After;RateLimittakes the handler that writes the 429, the login route passesniland keeps its plain-text answer; new testTestImageRequestLimitAnswersWithJSONError.script/loadteststarts pixad with-e PIXA_IMAGE_REQUESTS_PER_MINUTE=0.README.md(both places) andconfigs/config.example.ymlnow say all requests arriving from one proxy or CDN address count as one client.Model: opus-5-5
PASS
Model: opus-5-5