From 1b2434e56fc6bc8c85878cf252b09ce076e622fc Mon Sep 17 00:00:00 2001 From: Paulo Costa Date: Thu, 20 Apr 2023 12:07:37 -0300 Subject: [PATCH] Detach asynchronous request from current context --- httpcache.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/httpcache.go b/httpcache.go index b54f0ef..4daf830 100644 --- a/httpcache.go +++ b/httpcache.go @@ -8,6 +8,7 @@ package httpcache import ( "bufio" "bytes" + "context" "errors" "io" "io/ioutil" @@ -107,6 +108,8 @@ type Transport struct { Cache Cache // If true, responses returned from the cache will be given an extra header, X-From-Cache MarkCachedResponses bool + // Context timeout for async requests triggered by stale-while-revalidate + AsyncRevalidateTimeout time.Duration } // NewTransport returns a new Transport with the @@ -171,11 +174,18 @@ func (t *Transport) RoundTrip(req *http.Request) (resp *http.Response, err error if freshness == fresh { return cachedResp, nil } else if freshness == staleWhileRevalidate { - noCacheRequest := *req - noCacheRequest.Header = noCacheRequest.Header.Clone() + bgContext := context.Background() + var cancelContext context.CancelFunc = nil + if t.AsyncRevalidateTimeout > 0 { + bgContext, cancelContext = context.WithTimeout(bgContext, t.AsyncRevalidateTimeout) + } + noCacheRequest := req.Clone(bgContext) noCacheRequest.Header.Set("cache-control", "no-cache") go func() { - resp, err := t.RoundTrip(&noCacheRequest) + if cancelContext != nil { + defer cancelContext() + } + resp, err := t.RoundTrip(noCacheRequest) if err == nil { defer resp.Body.Close() buffer := make([]byte, 4096)