Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(sw): return 200-299,304 responses immediately #383

Merged
merged 3 commits into from
Sep 23, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 43 additions & 8 deletions sw/CacheChildrenStrategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ const log = {
*/
const CACHE_VERSION = 'v1'

/**
* The maximum allowed age of the sw cache in milliseconds.
*/
// const MAX_SW_CACHE_AGE = 1000 * 60 * 5

// Based on Java's hashCode implementation: https://stackoverflow.com/a/7616484/104380
const generateHashCode = str => [...str].reduce((hash, chr) => 0 | (31 * hash + chr.charCodeAt(0)), 0)

Expand All @@ -25,6 +30,31 @@ contentHashDB.version(1).stores({
hashes: `cacheKey, hashCode`
});

/**
* check if the cached response is valid:
* 1. Not null
* 2. 200-299 or 304 response
* 3. Not too old (not greater than MAX_SW_CACHE_AGE)
*/
function isCachedResponseStillValid (cachedResponse?: Response): cachedResponse is Response {
if (!cachedResponse) {
return false
}
if (!cachedResponse.ok || cachedResponse.status === 304) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can merge the two if statements.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, i was just trying to keep them separate and explicit for clarity

return false
}

// leaving if we need it, but will remove in PR if preview is good.
// const cachedResponseDate = cachedResponse.headers.get('Date')
// const cachedResponseAge = cachedResponseDate != null ? Date.now() - new Date(cachedResponseDate).getTime() : Infinity

// if (cachedResponseAge > MAX_SW_CACHE_AGE) {
// return false
// }

return true
}

/**
* This is a custom strategy to cache the milestone children of a Starmap.
* The benefit of writing this as a workbox strategy is we can use other workbox plugins like expiration.
Expand Down Expand Up @@ -84,21 +114,26 @@ export class CacheChildren extends Strategy implements Strategy {
let cachedResponse = await handler.cacheMatch(cacheKey)
log.debug(`response(cached) x-vercel-cache header: ${cachedResponse?.headers?.get('x-vercel-cache')}`)

if (isCachedResponseStillValid(cachedResponse)) {
// We have a cached response with 200-299 (status.ok) or 304 ("Not Modified") response, return it immediately.
return cachedResponse
}

/**
* We don't have a valid cached response. We need to fetch the actual response, and populate the cache with it.
*/
log.debug('No valid cached response found. Waiting for populateCacheAsync to finish')

const actualResponse = handler.fetch(request.clone())
const populateCachePromise = this.populateCacheAsync(cacheKey, actualResponse, handler)
// WARNING: We're not awaiting this call deliberately. We want to populate the cache in the background.
// Essentially, poor-man's version of stale-while-revalidate.
// handler will wait till this promise resolves. This can be monitored using the `doneWaiting` method.
void handler.waitUntil(populateCachePromise)
if (!cachedResponse || !cachedResponse.ok) {
log.debug('No valid cached response found. Waiting for populateCacheAsync to finish')
await handler.doneWaiting()
log.debug('populateCacheAsync finished. Getting cached response')
cachedResponse = await handler.cacheMatch(cacheKey)
log.debug('Got cached response')
}
await handler.doneWaiting()
log.debug('populateCacheAsync finished. Returning actual response')

return cachedResponse ?? actualResponse
return actualResponse
} catch (error) {
throw new Error(`Custom Caching of Children Failed with error: ${error}`)
}
Expand Down