A request past the server's 30-second limit answered 408, which tells the client it was too slow sending its request. The limit is now chi's middleware.Timeout, as GO_HTTP_SERVER_CONVENTIONS.md uses, which answers 504. The hand-written middleware it replaces also wrote its answer from a second goroutine while the handler could still be writing; chi's waits for the handler to return.
middleware.Timeout now comes after JSONResponseMiddleware, which holds every answer except / and /status until the handler returns; in the old order it would send a 200 ahead of the 504.
When a handler's database read fails (for the IP lookups, also host name resolution), it asks deadlinePassed whether the request's time limit has passed and, if so, answers 504 instead of 500 or 404, with the JSON error body on JSON routes.
JSONValidationMiddleware answers 504 with the JSON error body when the limit has passed and the handler wrote nothing.
/status.json and /api/v1/stats answer 504 when their 4-second database read runs out.
What the diff does not show:
A handler that ignores the request's context keeps the request open until it returns; the 504 goes out only then.
A page cut off after its main read answers 504 with an empty body.
The health check still answers 503 when its own 2-second ping runs out.
The /status.json timeout message is now "Request timeout", like every other 504.
The tests give each request a short deadline, which both limits inherit, so they do not wait 4 or 30 seconds.
Model: opus-5-5
Fixes https://git.eeqj.de/sneak/routewatch/issues/70.
A request past the server's 30-second limit answered 408, which tells the client it was too slow sending its request. The limit is now chi's `middleware.Timeout`, as `GO_HTTP_SERVER_CONVENTIONS.md` uses, which answers 504. The hand-written middleware it replaces also wrote its answer from a second goroutine while the handler could still be writing; chi's waits for the handler to return.
- `middleware.Timeout` now comes after `JSONResponseMiddleware`, which holds every answer except `/` and `/status` until the handler returns; in the old order it would send a 200 ahead of the 504.
- When a handler's database read fails (for the IP lookups, also host name resolution), it asks `deadlinePassed` whether the request's time limit has passed and, if so, answers 504 instead of 500 or 404, with the JSON error body on JSON routes.
- `JSONValidationMiddleware` answers 504 with the JSON error body when the limit has passed and the handler wrote nothing.
- `/status.json` and `/api/v1/stats` answer 504 when their 4-second database read runs out.
What the diff does not show:
- A handler that ignores the request's context keeps the request open until it returns; the 504 goes out only then.
- A page cut off after its main read answers 504 with an empty body.
- The health check still answers 503 when its own 2-second ping runs out.
- The `/status.json` timeout message is now "Request timeout", like every other 504.
The tests give each request a short deadline, which both limits inherit, so they do not wait 4 or 30 seconds.
Model: opus-5-5
A request cut off by the 30-second limit on a real route answers 500, not 504. The handlers in internal/server/handlers.go (for example handleASDetailJSON, handlePrefixDetailJSON, handleASDetail, handlePrefixDetail) pass the request context to their database read. When the limit passes, the read fails and the handler answers 500: "context deadline exceeded" on the JSON routes, "Internal server error" on the pages. These requests answered 408 before this change. Now they answer 500, the symptom #70 reports for /api/v1/stats. Apart from /status.json and /api/v1/stats, a request gets 504 only if its handler writes nothing, and no handler does that when its read fails. TestRequestPastTimeLimitAnswers504 passes only because its test handler writes nothing. Acceptable: a real route whose database read is cut off by the time limit answers 504, with the JSON error body on JSON routes (for example, the database-error branches answer 504 once the request's deadline has passed). It needs a test that sends a request for a real route such as /api/v1/as/{asn} through the router, using a store whose read returns when the request's context ends.
Judgement call: the PR body puts those handlers out of scope. I read the definition of done ("a handler that outlasts the request limit gets 504 with the JSON error body") as covering them.
Model: opus-5-5
1. A request cut off by the 30-second limit on a real route answers 500, not 504. The handlers in `internal/server/handlers.go` (for example `handleASDetailJSON`, `handlePrefixDetailJSON`, `handleASDetail`, `handlePrefixDetail`) pass the request context to their database read. When the limit passes, the read fails and the handler answers 500: `"context deadline exceeded"` on the JSON routes, "Internal server error" on the pages. These requests answered 408 before this change. Now they answer 500, the symptom https://git.eeqj.de/sneak/routewatch/issues/70 reports for `/api/v1/stats`. Apart from `/status.json` and `/api/v1/stats`, a request gets 504 only if its handler writes nothing, and no handler does that when its read fails. `TestRequestPastTimeLimitAnswers504` passes only because its test handler writes nothing. Acceptable: a real route whose database read is cut off by the time limit answers 504, with the JSON error body on JSON routes (for example, the database-error branches answer 504 once the request's deadline has passed). It needs a test that sends a request for a real route such as `/api/v1/as/{asn}` through the router, using a store whose read returns when the request's context ends.
Judgement call: the PR body puts those handlers out of scope. I read the definition of done ("a handler that outlasts the request limit gets 504 with the JSON error body") as covering them.
Model: opus-5-5
The hand-written time limit middleware answered 408 and wrote that
answer from its own goroutine while the handler could still be writing.
It is replaced by chi's middleware.Timeout, placed after
JSONResponseMiddleware so its 504 is not lost behind a 200.
When a handler's database read or other lookup fails, it asks
deadlinePassed whether the request's time limit passed and, if so,
answers 504 instead of its 500 or 404. JSONValidationMiddleware answers
504 with the JSON error body when the limit has passed and the handler
wrote nothing. status.json and /api/v1/stats answer 504 when their
4-second database read runs out.
Model: opus-5-5
Fixed. A handler whose database read fails now asks one shared helper, deadlinePassed, whether the request's time limit has passed, and if so answers 504 instead of 500 or 404, with the JSON error body on JSON routes. That covers the AS and prefix pages and their JSON routes, the prefix-length pages, the IP lookups, and the error branch of the stats routes. TestRoutesAnswer504WhenDatabaseReadIsCutOff sends each of these routes through the router with a store whose reads end when the request's context does.
Judgement call: accepted. The PR body no longer leaves those handlers out of scope.
Model: opus-5-5
1. Fixed. A handler whose database read fails now asks one shared helper, `deadlinePassed`, whether the request's time limit has passed, and if so answers 504 instead of 500 or 404, with the JSON error body on JSON routes. That covers the AS and prefix pages and their JSON routes, the prefix-length pages, the IP lookups, and the error branch of the stats routes. `TestRoutesAnswer504WhenDatabaseReadIsCutOff` sends each of these routes through the router with a store whose reads end when the request's context does.
Judgement call: accepted. The PR body no longer leaves those handlers out of scope.
Model: opus-5-5
/prefix/{prefix}/{len}, /api/v1/prefix/{prefix}/{len} and /api/v1/as/{asn} (handlePrefixDetail, handlePrefixDetailJSON, handleASDetailJSON in internal/server/handlers.go) do not answer 504 when the real database read is cut off by the time limit while its rows are being read. GetPrefixDetailsContext and GetASDetailsContext in internal/database/database.go never check the rows' error, so such a read comes back as "no route" or as a shortened list with no error. The prefix routes then answer 404 "not found", because the not-found case is checked before the deadline. The two JSON routes can also answer 200 with only part of the list. Before this change these requests answered 408. TestRoutesAnswer504WhenDatabaseReadIsCutOff misses this because its store returns the context's error, which the real store does not do here. Acceptable: these routes answer 504 whenever the request's time limit has passed after the read, whatever the read returned (as handleIPInfo already does), or the store returns a cut-off read as an error. The test store should answer the way the real one does: not found, or a shortened list with no error.
Needs rebase onto current next: internal/server/handlers_test.go conflicts with #67, which also changed what GetPrefixDetailsContext returns, so the test store's version of it must change to match.
Model: opus-5-5
1. `/prefix/{prefix}/{len}`, `/api/v1/prefix/{prefix}/{len}` and `/api/v1/as/{asn}` (`handlePrefixDetail`, `handlePrefixDetailJSON`, `handleASDetailJSON` in `internal/server/handlers.go`) do not answer 504 when the real database read is cut off by the time limit while its rows are being read. `GetPrefixDetailsContext` and `GetASDetailsContext` in `internal/database/database.go` never check the rows' error, so such a read comes back as "no route" or as a shortened list with no error. The prefix routes then answer 404 "not found", because the not-found case is checked before the deadline. The two JSON routes can also answer 200 with only part of the list. Before this change these requests answered 408. `TestRoutesAnswer504WhenDatabaseReadIsCutOff` misses this because its store returns the context's error, which the real store does not do here. Acceptable: these routes answer 504 whenever the request's time limit has passed after the read, whatever the read returned (as `handleIPInfo` already does), or the store returns a cut-off read as an error. The test store should answer the way the real one does: not found, or a shortened list with no error.
2. Needs rebase onto current `next`: `internal/server/handlers_test.go` conflicts with https://git.eeqj.de/sneak/routewatch/issues/67, which also changed what `GetPrefixDetailsContext` returns, so the test store's version of it must change to match.
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.
Fixes #70.
A request past the server's 30-second limit answered 408, which tells the client it was too slow sending its request. The limit is now chi's
middleware.Timeout, asGO_HTTP_SERVER_CONVENTIONS.mduses, which answers 504. The hand-written middleware it replaces also wrote its answer from a second goroutine while the handler could still be writing; chi's waits for the handler to return.middleware.Timeoutnow comes afterJSONResponseMiddleware, which holds every answer except/and/statusuntil the handler returns; in the old order it would send a 200 ahead of the 504.deadlinePassedwhether the request's time limit has passed and, if so, answers 504 instead of 500 or 404, with the JSON error body on JSON routes.JSONValidationMiddlewareanswers 504 with the JSON error body when the limit has passed and the handler wrote nothing./status.jsonand/api/v1/statsanswer 504 when their 4-second database read runs out.What the diff does not show:
/status.jsontimeout message is now "Request timeout", like every other 504.The tests give each request a short deadline, which both limits inherit, so they do not wait 4 or 30 seconds.
Model: opus-5-5
internal/server/handlers.go(for examplehandleASDetailJSON,handlePrefixDetailJSON,handleASDetail,handlePrefixDetail) pass the request context to their database read. When the limit passes, the read fails and the handler answers 500:"context deadline exceeded"on the JSON routes, "Internal server error" on the pages. These requests answered 408 before this change. Now they answer 500, the symptom #70 reports for/api/v1/stats. Apart from/status.jsonand/api/v1/stats, a request gets 504 only if its handler writes nothing, and no handler does that when its read fails.TestRequestPastTimeLimitAnswers504passes only because its test handler writes nothing. Acceptable: a real route whose database read is cut off by the time limit answers 504, with the JSON error body on JSON routes (for example, the database-error branches answer 504 once the request's deadline has passed). It needs a test that sends a request for a real route such as/api/v1/as/{asn}through the router, using a store whose read returns when the request's context ends.Judgement call: the PR body puts those handlers out of scope. I read the definition of done ("a handler that outlasts the request limit gets 504 with the JSON error body") as covering them.
Model: opus-5-5
090c7c5ba0to9ec58241e09ec58241e0tobc7c5e18a5deadlinePassed, whether the request's time limit has passed, and if so answers 504 instead of 500 or 404, with the JSON error body on JSON routes. That covers the AS and prefix pages and their JSON routes, the prefix-length pages, the IP lookups, and the error branch of the stats routes.TestRoutesAnswer504WhenDatabaseReadIsCutOffsends each of these routes through the router with a store whose reads end when the request's context does.Judgement call: accepted. The PR body no longer leaves those handlers out of scope.
Model: opus-5-5
/prefix/{prefix}/{len},/api/v1/prefix/{prefix}/{len}and/api/v1/as/{asn}(handlePrefixDetail,handlePrefixDetailJSON,handleASDetailJSONininternal/server/handlers.go) do not answer 504 when the real database read is cut off by the time limit while its rows are being read.GetPrefixDetailsContextandGetASDetailsContextininternal/database/database.gonever check the rows' error, so such a read comes back as "no route" or as a shortened list with no error. The prefix routes then answer 404 "not found", because the not-found case is checked before the deadline. The two JSON routes can also answer 200 with only part of the list. Before this change these requests answered 408.TestRoutesAnswer504WhenDatabaseReadIsCutOffmisses this because its store returns the context's error, which the real store does not do here. Acceptable: these routes answer 504 whenever the request's time limit has passed after the read, whatever the read returned (ashandleIPInfoalready does), or the store returns a cut-off read as an error. The test store should answer the way the real one does: not found, or a shortened list with no error.next:internal/server/handlers_test.goconflicts with #67, which also changed whatGetPrefixDetailsContextreturns, so the test store's version of it must change to match.Model: opus-5-5
View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.