Count an oversized DoH body as a failed attempt (#760) - #775
Merged
Conversation
Every other unusable response in resolve() reports through reportFailedAttempt() before retrying; the two oversized-body branches did not. DnsProxyServer floors the per-query cost at Math.max(1, queryFailedAttempts.get()), so an endpoint returning nothing but oversized bodies was charged one failure per query however many attempts it burned -- ten whole queries to trip the circuit breaker where every other failure mode takes three. Covers both the declared-Content-Length and the chunked path. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #760.
DnsOverHttpsClient.resolve()reports every unusable response throughreportFailedAttempt()before retrying — a 5xx, a null body, a sub-12-byteanswer, a non-cancelled
IOException. The two oversized-body branches added by#771 were the exception: they
continuewithout reporting.DnsProxyServercharges a failed queryMath.max(1, queryFailedAttempts.get()),so this was not "never trips the breaker" — the floor of 1 still applies. But it
did mean an endpoint returning nothing but oversized bodies cost one failure
per query however many attempts it burned, so it took ten whole queries to reach
CIRCUIT_BREAKER_THRESHOLDwhere every other failure mode takes three. That isexactly the per-attempt accounting #768 introduced, applied to the one path that
missed it.
Two lines, plus regression coverage for both the declared-
Content-Lengthandthe chunked path (the latter is only caught after
peekBody, so it needs its owntest).
What is not changed
The other half of #760 —
dohFailures.set(0)on any success — is left alonedeliberately. #768 made each wasted attempt count, so a flapping endpoint now
trips after ~3–4 bad queries rather than needing ten consecutive clean failures,
which defuses the original report. Resetting on success is the fail-open
behaviour we want for a DNS path that must not stay broken.
Verification
./gradlew :app:testGithubDebugUnitTest --tests '…DnsOverHttpsClientTest'— 24 tests, 0 failures.the two new tests fail (
expected:<3> but was:<0>andexpected:<1> but was:<0>)and no others — so they test the fix rather than passing vacuously.
🤖 Generated with Claude Code