Skip to content

fix(hub): strengthen retries for bucket metadata gateway errors - #215

Open
arekborucki wants to merge 9 commits into
huggingface:mainfrom
arekborucki:fix/hub-retry-gateway-timeouts
Open

fix(hub): strengthen retries for bucket metadata gateway errors#215
arekborucki wants to merge 9 commits into
huggingface:mainfrom
arekborucki:fix/hub-retry-gateway-timeouts

Conversation

@arekborucki

@arekborucki arekborucki commented Aug 9, 2026

Copy link
Copy Markdown

Summary

During the 2026-08-09 docs outage, hf-mount sidecars on hub-doc hit repeated 504 responses from /api/buckets/.../tree while mongodb-moonlanding-bucket-prod config servers were electing. The client already retried transient Hub errors, but without a total operation budget or stale-metadata fallback, FUSE lookups could hang long enough to trip Better Uptime (30s).

This PR hardens the client side of that path:

  • Keep default retries at 2 (3 total attempts) — no aggressive 5-try / 15s gateway backoff
  • Operation deadline (--hub-operation-deadline-ms, default 3000ms): wall-clock budget for the whole operation. Each in-flight send() is wrapped in tokio::time::timeout(remaining) so hung requests cannot ignore the budget via the 60s/30s reqwest client timeouts. Intentionally shorter than the Hub's Mongo tree-listing deadline.
  • Full jitter on exponential backoff (500ms base) to spread retry waves across mounts
  • Circuit breaker: after 3 consecutive 502/503/504, skip retries for 10s; counter resets when cooldown expires (half-open)
  • Stale listing fallback: when list_tree fails transiently but a cached remote listing exists, serve it via stale_listing_since (does not reset children_loaded_at). Includes empty directories (children_from_remote without requiring non-empty children).
  • Progressive stale refresh backoff: 5s → 10s → 30s between list_tree retries per directory during outages
  • HEAD lookup fallback (read-only mounts only): on retryable HEAD failure, serve cached inode if present
  • Negative cache unchanged for stale listings: ENOENT negatives only from fresh children_loaded() listings, not stale snapshots
  • CLI flags: --hub-max-retries, --hub-operation-deadline-ms, --hub-request-timeout-secs, --hub-head-request-timeout-secs

Context

Incident chain: cfg election → bucketDb metadata ~1.3s → Hub timeoutListingsMs (~5s) → 504 → FUSE EIO → /docs/* slow/down.

Server-side fixes (moon-landing deadline/retry, Mongo pacing) are complementary; this protects all hf-mount consumers (docs, Spaces volumes, etc.).

Deploy caveat

Stale metadata fallback is in-memory only. Rolling hub-doc pods (required to pick up a new hf-mount image) clears any warm listing cache — freshly restarted pods have no stale fallback until they have successfully listed the tree at least once. Plan deploy accordingly (e.g. avoid simultaneous mass restart during known bucket maintenance, or accept a brief cold-start window).

Deploy path after merge

  1. Cut hf-mount release (or use commit SHA)
  2. Bump hfMount.image.tag in infra/projects/hub/05-eks-utils/hf_csi_driver.tf (currently v0.9.0)
  3. Roll CSI driver / restart hub-doc pods (see caveat above)

Test plan

  • CI (cargo fmt --check, cargo test --lib, integration tests)
  • Manual: mount hf-doc-build/doc read-only, simulate 504 on tree endpoint, verify stale cache serves and negative cache is not populated from stale listing
  • Manual: verify operation deadline aborts a slow/hung Hub response within ~3s (not 60s reqwest timeout)
  • Staging: deploy new hf-mount tag on one hub-doc pod, confirm docs load during induced bucket metadata latency

arekborucki and others added 9 commits August 9, 2026 13:26
Hub bucket tree/HEAD calls already retried 504s, but only twice with
short backoff — not enough to ride out MongoDB config-server elections
that stall metadata for tens of seconds.

- Raise default max retries from 2 to 4 (5 total attempts)
- Use longer 1s/2s/4s/8s backoff on 502/503/504
- Add --hub-max-retries and --hub-request-timeout-secs CLI flags
- Reuse cached directory listings when list_tree fails transiently after
  poll invalidation (read-only mounts keep serving docs)

Co-authored-by: Cursor <cursoragent@cursor.com>
Revert aggressive 5-try/15s gateway backoff in favor of fail-fast within
a 5s operation budget, full jitter on retries, and a short-lived circuit
breaker after consecutive 502/503/504. Extend stale metadata fallback to
HEAD lookups and mark stale listings without faking fresh children_loaded_at.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Only populate negative dentry cache from fresh listings (children_loaded),
not stale snapshots. Escalate stale list_tree retry interval 5s→10s→30s.
Default hub operation deadline 3s (fail fast vs server Mongo timeout).
Gate HEAD lookup stale fallback on read-only mounts. Check HTTP deadline
before each attempt, not only before backoff sleep.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Wrap each send() in tokio::time::timeout(remaining) so the 3s operation
budget applies to hung requests, not just between retries. Reset circuit
failure counter when the cooldown expires (half-open). Allow stale fallback
for empty remote-backed directories. Fix operation_deadline_ms doc comment.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…504.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
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