@@ -30,12 +30,12 @@ func calculateSoftTTL(respUnix, expiresAt int64, fuzzyRate float64) int64 {
3030 if hardTTL <= 0 {
3131 return expiresAt
3232 }
33-
33+
3434 // Ensure fuzzy rate is in valid range (0, 1.0]
3535 if fuzzyRate <= 0 || fuzzyRate > 1 {
3636 fuzzyRate = 0.8 // default to 0.8 if invalid
3737 }
38-
38+
3939 softTTL := int64 (float64 (hardTTL ) * fuzzyRate )
4040 return respUnix + softTTL
4141}
@@ -48,22 +48,22 @@ func shouldTriggerFuzzyRefresh(now, softTTL, hardTTL int64) bool {
4848 // Before soft TTL, no refresh needed
4949 return false
5050 }
51-
51+
5252 if now >= hardTTL {
5353 // After hard TTL, force refresh (handled by hasExpired)
5454 return false
5555 }
56-
56+
5757 // In the fuzzy refresh zone [soft_ttl, hard_ttl)
5858 // Calculate linear probability: P = (now - soft_ttl) / (hard_ttl - soft_ttl)
5959 totalWindow := float64 (hardTTL - softTTL )
6060 if totalWindow <= 0 {
6161 return false
6262 }
63-
63+
6464 elapsed := float64 (now - softTTL )
6565 probability := elapsed / totalWindow
66-
66+
6767 // Random trigger based on probability using math/rand/v2 which is thread-safe
6868 return rand .Float64 () < probability
6969}
@@ -72,14 +72,14 @@ func (r *RevalidateProcessor) Lookup(c *Caching, req *http.Request) (bool, error
7272 if c .md == nil {
7373 return false , nil
7474 }
75-
75+
7676 now := time .Now ().Unix ()
7777 hardTTL := c .md .ExpiresAt
78-
78+
7979 // Fuzzy Refresh Logic
8080 if c .opt .FuzzyRefresh && c .opt .FuzzyRefreshRate > 0 {
8181 softTTL := calculateSoftTTL (c .md .RespUnix , c .md .ExpiresAt , c .opt .FuzzyRefreshRate )
82-
82+
8383 // Check if we're in the fuzzy refresh zone [soft_ttl, hard_ttl)
8484 if now >= softTTL && now < hardTTL {
8585 // We're in the fuzzy refresh zone
@@ -90,17 +90,17 @@ func (r *RevalidateProcessor) Lookup(c *Caching, req *http.Request) (bool, error
9090 c .id .Key (),
9191 time .Unix (softTTL , 0 ).Format (time .DateTime ),
9292 time .Unix (hardTTL , 0 ).Format (time .DateTime ))
93-
93+
9494 // Trigger async revalidation in background
9595 go r .asyncRevalidate (c , req )
9696 }
9797 }
98-
98+
9999 // Still return cache hit - serve stale content while refreshing
100100 return true , nil
101101 }
102102 }
103-
103+
104104 // check if metadata is expired (hard expiration).
105105 if ! hasExpired (c .md ) {
106106 return true , nil
@@ -236,38 +236,39 @@ func (r *RevalidateProcessor) asyncRevalidate(c *Caching, req *http.Request) {
236236 // Create a background context with timeout
237237 ctx , cancel := context .WithTimeout (context .Background (), 30 * time .Second )
238238 defer cancel ()
239-
239+
240240 // Clone the request for background processing
241241 bgReq := req .Clone (ctx )
242-
242+
243243 // Set conditional headers for revalidation
244244 if c .md .Headers .Get ("ETag" ) != "" {
245245 bgReq .Header .Set ("If-None-Match" , c .md .Headers .Get ("ETag" ))
246246 }
247247 if c .md .Headers .Get ("Last-Modified" ) != "" {
248248 bgReq .Header .Set ("If-Modified-Since" , c .md .Headers .Get ("Last-Modified" ))
249249 }
250-
250+
251251 // Remove Range header for full object revalidation
252252 bgReq .Header .Del ("Range" )
253-
253+
254254 c .log .Debugf ("async fuzzy refresh started for object: %s" , c .id .Key ())
255-
255+
256256 // Perform the upstream request
257257 resp , err := c .doProxy (bgReq , false )
258+ defer closeBody (resp ) // always check resp nil
259+
258260 if err != nil {
259261 c .log .Warnf ("async fuzzy refresh failed for object %s: %v" , c .id .Key (), err )
260262 return
261263 }
262- defer closeBody (resp )
263-
264+
264265 // Handle 304 Not Modified - just update freshness metadata
265266 if resp .StatusCode == http .StatusNotModified {
266267 r .freshness (c , resp )
267268 c .log .Debugf ("async fuzzy refresh completed (304) for object: %s" , c .id .Key ())
268269 return
269270 }
270-
271+
271272 // For non-304 responses, the content has changed
272273 // The doProxy method has already wrapped the response body with cache writing logic
273274 // We need to consume the body to trigger the cache update
@@ -282,7 +283,7 @@ func (r *RevalidateProcessor) asyncRevalidate(c *Caching, req *http.Request) {
282283 c .log .Debugf ("async fuzzy refresh completed (%d) for object: %s - content updated" , resp .StatusCode , c .id .Key ())
283284 return
284285 }
285-
286+
286287 c .log .Debugf ("async fuzzy refresh completed (%d) for object: %s" , resp .StatusCode , c .id .Key ())
287288}
288289
0 commit comments