(err error)
| 529 | func (p *CacheProxy) fetchFromPeer(holder string, flight bool, cacheKey string, r *http.Request) (fetchResult, bool) { |
| 530 | n, ok := p.peers.FetchFromPeer(r.Context(), holder, cacheKey, flight, func(body io.Reader) (int64, error) { |
| 531 | return p.store.PutStream(cacheKey, body) |
| 532 | }) |
| 533 | if !ok { |
| 534 | return fetchResult{}, false |
| 535 | } |
| 536 | cacheBytesServed.WithLabelValues("peer").Add(float64(n)) |
| 537 | return fetchResult{size: n, source: "peer"}, true |
| 538 | } |
| 539 | |
| 540 | // fetchOrigin forwards the request verbatim (headers, Host, signature) to the |
| 541 | // real origin and streams a successful body straight to the on-disk cache, |
| 542 | // returning the stored size and Content-Type. The SigV4 signature remains valid |
| 543 | // because the URL and Host header are unchanged. Streaming to disk (rather than |
| 544 | // io.ReadAll into a []byte) is what keeps proxy memory flat under concurrent |
| 545 | // large range reads. A non-2xx response is NOT cached — its (capped) error body |
| 546 | // is captured and returned as an originStatusError for verbatim forwarding. |
| 547 | func (p *CacheProxy) fetchOrigin(cacheKey string, r *http.Request) (int64, string, error) { |
| 548 | _, originSpan := proxyTracer.Start(r.Context(), "cache.origin_fetch") |
| 549 | defer originSpan.End() |
| 550 | |
| 551 | var size int64 |
| 552 | var contentType string |
| 553 | err := p.retryOriginFetch(r, originSpan, func() error { |
| 554 | var attemptErr error |
| 555 | size, contentType, attemptErr = p.fetchOriginOnce(cacheKey, r) |
| 556 | return attemptErr |
| 557 | }) |
| 558 | if err != nil { |
| 559 | return 0, "", err |
| 560 | } |
| 561 | originSpan.SetAttributes(attribute.Int64("duckgres.bytes", size)) |
| 562 | return size, contentType, nil |
| 563 | } |
| 564 | |
| 565 | // retryOriginFetch runs attempt (one origin fetch) up to |
| 566 | // originRetryMaxAttempts times with jittered exponential backoff, while the |
| 567 | // error is retriable (isRetriableOriginFetchError) and the request context is |
no test coverage detected