fix(relay/media): fall back to full download when S3 range GET fails (#3786) - #4079
Open
iroiro147 wants to merge 3 commits into
Open
fix(relay/media): fall back to full download when S3 range GET fails (#3786)#4079iroiro147 wants to merge 3 commits into
iroiro147 wants to merge 3 commits into
Conversation
Adds a root-level `buzz doctor` subcommand that runs independent local + remote readiness checks and aggregates them into a single structured JSON report. Use it to answer 'is my Buzz environment ready to use?' without publishing events or mutating state. Checks performed: - relay URL presence, syntax, canonicalization - BUZZ_PRIVATE_KEY parseability (never printed; only the derived public identity is reported) - BUZZ_AUTH_TAG syntax + verification against the signing identity (never printed) - CLI version - relay unauthenticated reachability probe - NIP-11 parseation against the relay info document - authenticated read probe (single bounded query) - community membership probe (kind:39002 #p=self) `--offline` runs only local checks and marks remote probes as skipped. Missing or malformed config surfaces as a check result with status error, not as an argument-time failure, so doctor remains useful when the environment being debugged is the broken one. Exit behavior distinguishes failed required checks from warnings: 0 all applicable checks ok (warnings allowed) 3 any auth/identity check failed 2 any relay/network check failed All applicable checks run so one invocation can reveal multiple problems. Tests cover the aggregator's exit-precedence (auth wins over network, skipped never affects outcome, warnings stay zero) and the JSON output shape. Signed-off-by: iroiro147 <sarthak.singh@juspay.in>
… not auth (exit 3) (block#3926) The first cut routed every authed-read failure into the same auth-shaped bucket. On an unreachable relay the relay_reachable probe was reported error, then the authed read ALSO reported auth_read error, which the aggregator mapped to exit 3 — even though a DNS/connect failure has nothing to do with credentials. Split the failure handling: - Distinguish true auth rejections (Auth variant, or relay 401/403) from transport/other relay failures. Only the former produces an auth_read error -> exit 3. - Track whether the unauthenticated reachability probe already failed; if so, skip re-emitting the relay-side error and mark auth_read/membership as skipped instead. - If reachability passed but the authed read failed for a transport reason, emit a relay_reachable error explaining the authed leg failed. Smoke-verified: with BUZZ_RELAY_URL pointing at an unresolvable host, exit is now 2 with relay_reachable + nip11 reporting the transport problem and auth_read/membership cleanly skipped. Signed-off-by: iroiro147 <sarthak.singh@juspay.in>
…lock#3786) Signed-off-by: iroiro147 <sarthak.singh@juspay.in>
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.
Problem — #3786
The
Rangehandler onGET /v1/mediareturns an opaque500 {"error":"internal error"}whenever the S3 range GET fails, even though the object exists and plain (non-range) GETs return 200 fine. This was reported for a ~9.9 MiB file stored on Cloudflare R2:Range: bytes=0-1023Range: bytes=0-99RangeheaderThe reporter verified the same object+range works directly via
aws s3api get-object --range bytes=0-99, so R2 itself handles ranges correctly — the failure path is inside buzz's handling of the range GET.Root-cause hypothesis
buzz-media::storage::get_range()callsbucket.get_object_range(...).rust-s3is built with thefail-on-errfeature, so any non-2xx from S3/R2 surfaces asS3Error::HttpFailWithBody(status, body). The existing code mapped onlyS3Error::Http(404, _)toNotFound; everything else fell through to a genericMediaError::StorageError, which the error handler turns into 500.The relay's range branch (
serve_blob_for_tenant) then propagated that 500 with no logging showing the upstream status/body — which is also why the reporters couldn't provide actionable diagnostics when asked.What this PR does
buzz-media::storage::get_range: mapHttpFailWithBodyexplicitly — logtracing::warn!(s3_status, s3_body, key, start, end)and surface a descriptiveStorageError(calling out 416 specifically) instead of the opaque one.buzz-relay::api::mediarange branch: on a failedget_range(exceptNotFound), log a warning and fall back to a fullget(&key), then slice[start..(end+1).min(len)]in memory. Returns 416 ifstart >= len. The existing response headers (includingContent-Range) are untouched since it's all keyed on the final slice.The fallback keeps the existing
MAX_RANGE_CHUNK-bounded behaviour intact: a legitimately huge file where the primary range GET succeeds is untouched. It's only used when S3 rejected the range GET in the first place, at which point we'd otherwise be returning 500.Unit tests for the new slice math and the clamping logic (including a regression-sized case matching the reporter's 9,896,517-byte object, plus a 20 MiB case where
MAX_RANGE_CHUNKbinds theend).Diagnostics
Going forward, if R2 (or any S3-compatible backend) rejects a range GET, the logs now contain the upstream HTTP status and body for the exact
key/start/end— precisely the information requested from the reporter in #3786 that they couldn't provide. The fallback means they'd also no longer see a 500 in this scenario.Testing