Skip to content

fix: Fix flaky cache revalidation tests caused by sub-millisecond max-age#2116

Open
55728 wants to merge 1 commit intocapricorn86:masterfrom
55728:fix-flaky-cache-revalidation-tests
Open

fix: Fix flaky cache revalidation tests caused by sub-millisecond max-age#2116
55728 wants to merge 1 commit intocapricorn86:masterfrom
55728:fix-flaky-cache-revalidation-tests

Conversation

@55728
Copy link
Copy Markdown

@55728 55728 commented Mar 26, 2026

Problem

The cache revalidation tests in Fetch.test.ts intermittently fail on CI because they use max-age=0.0001 (0.1 milliseconds) for cache expiry.

In ResponseCache.ts, the cache entry's expiry is calculated as:

cachedResponse.expires = Date.now() + parseFloat(value) * 1000;
// With max-age=0.0001: expires = Date.now() + 0.1

Later in the same add() method, the entry is validated:

if (!cachedResponse.etag && (!cachedResponse.expires || cachedResponse.expires < Date.now())) {
    entries.splice(index, 1);  // Entry removed immediately!
    return null;
}

Since Date.now() has millisecond precision, if even 1ms passes between the expiry calculation and this validation check, the entry is considered expired and removed during insertion. The second fetch then makes a fresh request instead of a cache revalidation, returning the original response headers instead of the 304 revalidation headers.

Solution

  • Change max-age=0.0001 (0.1ms) to max-age=0.1 (100ms) — large enough to survive the cache insertion, small enough to expire within the test's wait period
  • Increase the wait from 100ms to 300ms — ensures the cache has reliably expired before the second fetch (200ms margin over the 100ms max-age)

Affected tests (4 test cases, 9 value sites + 4 wait sites):

  • Revalidates cache with a "If-Modified-Since" request for a GET response with "Cache-Control" set to a "max-age".
  • Updates cache after a failed revalidation with a "If-Modified-Since" request for a GET response with "Cache-Control" set to a "max-age".
  • Revalidates cache with a "If-None-Match" request for a HEAD response with an "Etag" header.
  • Updates cache after a failed revalidation with a "If-None-Match" request for a GET response with an "Etag" header.

Verification

All 103 Fetch tests pass. The same test that was failing on CI in #1910 and #2114 now has sufficient timing margin to pass reliably.

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