A request past its time limit answers 408, and /api/v1/stats answers 500 #70

Open
opened 2026-10-14 14:50:32 +02:00 by clawbot · 2 comments
Collaborator

TimeoutMiddleware in internal/server/middleware.go answers a request still running after 30 seconds with 408 Request Timeout. 408 tells the client it was too slow sending its request and invites it to send the request again; a limit on the server's own work answers 503 or 504 (the chi middleware.Timeout that GO_HTTP_SERVER_CONVENTIONS.md uses answers 504). handleStatusJSON in internal/server/handlers.go also answers 408 when its 4-second database read runs out, and handleStats writes nothing in that case, so JSONValidationMiddleware turns the empty answer into 500 Internal Server Error.

Failure scenario: a /api/v1/stats request whose route timestamp reads take more than 4 seconds on a busy disk answers 500, the symptom reported in #30; any page that runs over 30 seconds answers 408.

Severity: low

Definition of done

  • A test, failing before the fix: a handler that outlasts the request limit gets 504 with the JSON error body, and /api/v1/stats with a store that outlasts its 4-second limit gets 504, not 500.
  • make check passes.

Model: opus-5-5

`TimeoutMiddleware` in `internal/server/middleware.go` answers a request still running after 30 seconds with 408 Request Timeout. 408 tells the client it was too slow sending its request and invites it to send the request again; a limit on the server's own work answers 503 or 504 (the chi `middleware.Timeout` that `GO_HTTP_SERVER_CONVENTIONS.md` uses answers 504). `handleStatusJSON` in `internal/server/handlers.go` also answers 408 when its 4-second database read runs out, and `handleStats` writes nothing in that case, so `JSONValidationMiddleware` turns the empty answer into 500 Internal Server Error. Failure scenario: a `/api/v1/stats` request whose route timestamp reads take more than 4 seconds on a busy disk answers 500, the symptom reported in https://git.eeqj.de/sneak/routewatch/issues/30; any page that runs over 30 seconds answers 408. Severity: low ## Definition of done - A test, failing before the fix: a handler that outlasts the request limit gets 504 with the JSON error body, and `/api/v1/stats` with a store that outlasts its 4-second limit gets 504, not 500. - `make check` passes. Model: opus-5-5
clawbot self-assigned this 2026-10-14 14:50:32 +02:00
Author
Collaborator

Plan: replace the hand-written TimeoutMiddleware with chi's middleware.Timeout, as GO_HTTP_SERVER_CONVENTIONS.md does, so a request past its limit answers 504 with the JSON error body. The handlers already pass the request context to their database reads, so they return when the limit passes. This also removes the suspected race in the current middleware: on a timeout it writes the response from the request goroutine while the handler goroutine may still be writing. Added to the definition of done: no response is written from two goroutines (the new tests run under -race, as make test does), and handleStats/handleStatusJSON answer 504 themselves when their 4-second read runs out, instead of 408 or an empty body.

Model: opus-5-5

Plan: replace the hand-written `TimeoutMiddleware` with chi's `middleware.Timeout`, as `GO_HTTP_SERVER_CONVENTIONS.md` does, so a request past its limit answers 504 with the JSON error body. The handlers already pass the request context to their database reads, so they return when the limit passes. This also removes the suspected race in the current middleware: on a timeout it writes the response from the request goroutine while the handler goroutine may still be writing. Added to the definition of done: no response is written from two goroutines (the new tests run under `-race`, as `make test` does), and `handleStats`/`handleStatusJSON` answer 504 themselves when their 4-second read runs out, instead of 408 or an empty body. Model: opus-5-5
Author
Collaborator

Built in #80. Two steps beyond the plan: middleware.Timeout now comes after JSONResponseMiddleware, because in the old position that middleware sends a 200 before the 504; and JSONValidationMiddleware answers 504 with the JSON error body when the limit has passed and the handler wrote nothing, because chi's 504 has no body.

Model: opus-5-5

Built in https://git.eeqj.de/sneak/routewatch/pulls/80. Two steps beyond the plan: `middleware.Timeout` now comes after `JSONResponseMiddleware`, because in the old position that middleware sends a 200 before the 504; and `JSONValidationMiddleware` answers 504 with the JSON error body when the limit has passed and the handler wrote nothing, because chi's 504 has no body. Model: opus-5-5
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/routewatch#70