Skip to content

fix(flaresolverr): tell a slow server apart from an absent one - #143

Merged
lestex merged 1 commit into
mainfrom
flaresolverr/error-kinds
Oct 15, 2026
Merged

lestex merged 1 commit into
mainfrom
flaresolverr/error-kinds

Conversation

@lestex

@lestex lestex commented Oct 15, 2026

Copy link
Copy Markdown
Owner

Three faults found reviewing #142 after it merged, all in how a failure is
reported rather than in what the package does.

Every transport error was reported as unreachable, including timeouts:

flaresolverr: cannot reach http://localhost:8191 (… context deadline exceeded …) - is it running, and is the url right?

So FlareSolverr chewing on a hard challenge past the deadline told you to check a
server you could watch running, when the fix is more time. A daemon shutting down
mid-search said the same about nothing being wrong at all. This is the
distinction Error exists for, and internal/indexer already draws it - the two
packages now classify alike, by asking the error rather than consulting a clock.

The status was captured and never rendered, so a failure FlareSolverr would
not explain printed its URL and then nothing. Reachable by pointing the url at
something that answers JSON but is not FlareSolverr - a reverse proxy's error
page, another service on that port. The status is the only fact left in that
case, and it is now what gets said. KindServer and KindBadReply also separate
"FlareSolverr failed" from "that was not FlareSolverr", which are different
things to go and look at.

The per-request bound lived only in the default http.Client, so a caller
supplying its own - to share a transport, as the rutracker plugin is likely to -
silently lost it. A server that accepts the connection and never answers would
hang the call forever. The deadline moves into send, where it holds whichever
client is in use.

Each fix has a test that fails without it

Verified by reverting each one:

reverted what the test reported
classification kind = 0, want KindTimeout + the "is it running" message
the deadline in send hung out its full ten second limit
status rendering flaresolverr: http://127.0.0.1:50159: — nothing after the colon

Two things the tests themselves needed

The bound is timeout + 15s, so a test could not make it short: Config grows
an unexported slack, the same trick internal/indexer uses for its clock.

And the stand-in server waits on a channel the test closes rather than on the
request context - a handler that never returns makes httptest's Close hang,
and a test that fails by hanging is a bad test. I know because mine did, for ten
minutes, before I fixed it.

make check and go test -race clean; the suite runs in 0.25s.

Three faults found reviewing the package after it merged, all in how a
failure is reported rather than in what it does.

Every transport error was reported as "cannot reach ... is it running,
and is the url right?", including timeouts. So FlareSolverr chewing on a
hard challenge past the deadline told the user to go and check a server
they could see running, when the fix is more time. A daemon shutting down
mid-search said the same thing about nothing being wrong at all. This is
the distinction the Error type exists for, and internal/indexer already
draws it; the two packages now classify alike, by asking the error rather
than consulting a clock.

The status was captured and never rendered, so a failure FlareSolverr
would not explain printed its URL and then nothing. Reachable by pointing
the url at something that answers JSON but is not FlareSolverr - a
reverse proxy's error page, another service on that port. The status is
the only fact left in that case, and it is now what gets said. Errors
also distinguish "FlareSolverr failed" from "that was not FlareSolverr",
which are different things to go and look at.

The per-request bound lived only in the http.Client built when none was
supplied, so a caller passing its own - to share a transport, as the
plugin is likely to - silently lost it: a server that accepts the
connection and never answers would hang the call forever. The deadline
moves into send, where it holds whichever client is in use.

Each of the three has a test that fails without its fix, checked by
reverting them: the timeout one reports "cannot reach ... is it running",
the bound one hangs out its ten second limit, and the no-message one
prints a URL followed by nothing.

Those tests also needed the wait to be short, which it could not be: the
bound is the timeout plus a fixed fifteen second slack. Config grows an
unexported slack, the same trick internal/indexer uses for its clock. And
the stand-in server waits on a channel the test closes rather than on the
request context, because a handler that never returns makes httptest's
Close hang - a test that fails by hanging is a bad test.
@lestex
lestex merged commit 778f487 into main Oct 15, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant