Dynamic cache length overriding (#2755)
For the Endpoint badge: #2473. `request-handler.js` is such a bear. I’m looking forward to being able to rewrite it when the service refactor is done.
This commit is contained in:
@@ -89,19 +89,35 @@ function handleRequest(cacheHeaderConfig, handlerOptions) {
|
||||
|
||||
const allowedKeys = flattenQueryParams(handlerOptions.queryParams)
|
||||
const {
|
||||
cacheLength: serviceCacheLengthSeconds,
|
||||
cacheLength: serviceDefaultCacheLengthSeconds,
|
||||
fetchLimitBytes,
|
||||
} = handlerOptions
|
||||
|
||||
return (queryParams, match, end, ask) => {
|
||||
const reqTime = new Date()
|
||||
|
||||
setCacheHeaders({
|
||||
cacheHeaderConfig,
|
||||
serviceCacheLengthSeconds,
|
||||
queryParams,
|
||||
res: ask.res,
|
||||
})
|
||||
// `defaultCacheLengthSeconds` can be overridden by
|
||||
// `serviceDefaultCacheLengthSeconds` (either by category or on a badge-
|
||||
// by-badge basis). Then in turn that can be overridden by
|
||||
// `serviceOverrideCacheLengthSeconds` (which we expect to be used only in
|
||||
// the dynamic badge) but only if `serviceOverrideCacheLengthSeconds` is
|
||||
// longer than `serviceDefaultCacheLengthSeconds` and then the `maxAge`
|
||||
// query param can also override both of those but again only if `maxAge`
|
||||
// is longer.
|
||||
//
|
||||
// When the legacy services have been rewritten, all the code in here
|
||||
// will go away, which should achieve this goal in a simpler way.
|
||||
//
|
||||
// Ref: https://github.com/badges/shields/pull/2755
|
||||
function setCacheHeadersOnResponse(res, serviceOverrideCacheLengthSeconds) {
|
||||
setCacheHeaders({
|
||||
cacheHeaderConfig,
|
||||
serviceDefaultCacheLengthSeconds,
|
||||
serviceOverrideCacheLengthSeconds,
|
||||
queryParams,
|
||||
res,
|
||||
})
|
||||
}
|
||||
|
||||
analytics.noteRequest(queryParams, match)
|
||||
|
||||
@@ -123,6 +139,10 @@ function handleRequest(cacheHeaderConfig, handlerOptions) {
|
||||
const tooSoon = +reqTime - cached.time < cached.interval
|
||||
if (tooSoon || cached.dataChange / cached.reqs <= freqRatioMax) {
|
||||
const svg = makeBadge(cached.data.badgeData)
|
||||
setCacheHeadersOnResponse(
|
||||
ask.res,
|
||||
cached.data.badgeData.cacheLengthSeconds
|
||||
)
|
||||
makeSend(cached.data.format, ask.res, end)(svg)
|
||||
cachedVersionSent = true
|
||||
// We do not wish to call the vendor servers.
|
||||
@@ -140,9 +160,13 @@ function handleRequest(cacheHeaderConfig, handlerOptions) {
|
||||
return
|
||||
}
|
||||
if (requestCache.has(cacheIndex)) {
|
||||
const cached = requestCache.get(cacheIndex).data
|
||||
const svg = makeBadge(cached.badgeData)
|
||||
makeSend(cached.format, ask.res, end)(svg)
|
||||
const cached = requestCache.get(cacheIndex)
|
||||
const svg = makeBadge(cached.data.badgeData)
|
||||
setCacheHeadersOnResponse(
|
||||
ask.res,
|
||||
cached.data.badgeData.cacheLengthSeconds
|
||||
)
|
||||
makeSend(cached.data.format, ask.res, end)(svg)
|
||||
return
|
||||
}
|
||||
ask.res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate')
|
||||
@@ -155,6 +179,7 @@ function handleRequest(cacheHeaderConfig, handlerOptions) {
|
||||
extension = 'svg'
|
||||
}
|
||||
const svg = makeBadge(badgeData)
|
||||
setCacheHeadersOnResponse(ask.res)
|
||||
makeSend(extension, ask.res, end)(svg)
|
||||
}, 25000)
|
||||
|
||||
@@ -256,6 +281,7 @@ function handleRequest(cacheHeaderConfig, handlerOptions) {
|
||||
requestCache.set(cacheIndex, updatedCache)
|
||||
if (!cachedVersionSent) {
|
||||
const svg = makeBadge(badgeData)
|
||||
setCacheHeadersOnResponse(ask.res, badgeData.cacheLengthSeconds)
|
||||
makeSend(format, ask.res, end)(svg)
|
||||
}
|
||||
},
|
||||
|
||||
@@ -25,6 +25,16 @@ function fakeHandler(queryParams, match, sendBadge, request) {
|
||||
sendBadge(format, badgeData)
|
||||
}
|
||||
|
||||
function createFakeHandlerWithCacheLength(cacheLengthSeconds) {
|
||||
return function fakeHandler(queryParams, match, sendBadge, request) {
|
||||
const [, someValue, format] = match
|
||||
const badgeData = getBadgeData('testing', queryParams)
|
||||
badgeData.text[1] = someValue
|
||||
badgeData.cacheLengthSeconds = cacheLengthSeconds
|
||||
sendBadge(format, badgeData)
|
||||
}
|
||||
}
|
||||
|
||||
function fakeHandlerWithNetworkIo(queryParams, match, sendBadge, request) {
|
||||
const [, someValue, format] = match
|
||||
request('https://www.google.com/foo/bar', (err, res, buffer) => {
|
||||
@@ -198,6 +208,62 @@ describe('The request handler', function() {
|
||||
expect(res.headers.get('cache-control')).to.equal('max-age=900')
|
||||
})
|
||||
|
||||
it('should set the expected cache headers on cached responses', async function() {
|
||||
register({ cacheHeaderConfig: { defaultCacheLengthSeconds: 900 } })
|
||||
|
||||
// Make first request.
|
||||
await fetch(`${baseUrl}/testing/123.json`)
|
||||
|
||||
const res = await fetch(`${baseUrl}/testing/123.json`)
|
||||
const expectedExpiry = new Date(
|
||||
+new Date(res.headers.get('date')) + 900000
|
||||
).toGMTString()
|
||||
expect(res.headers.get('expires')).to.equal(expectedExpiry)
|
||||
expect(res.headers.get('cache-control')).to.equal('max-age=900')
|
||||
})
|
||||
|
||||
it('should let live service data override the default cache headers with longer value', async function() {
|
||||
camp.route(
|
||||
/^\/testing\/([^/]+)\.(svg|png|gif|jpg|json)$/,
|
||||
handleRequest(
|
||||
{ defaultCacheLengthSeconds: 300 },
|
||||
(queryParams, match, sendBadge, request) => {
|
||||
++handlerCallCount
|
||||
createFakeHandlerWithCacheLength(400)(
|
||||
queryParams,
|
||||
match,
|
||||
sendBadge,
|
||||
request
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
const res = await fetch(`${baseUrl}/testing/123.json`)
|
||||
expect(res.headers.get('cache-control')).to.equal('max-age=400')
|
||||
})
|
||||
|
||||
it('should not let live service data override the default cache headers with shorter value', async function() {
|
||||
camp.route(
|
||||
/^\/testing\/([^/]+)\.(svg|png|gif|jpg|json)$/,
|
||||
handleRequest(
|
||||
{ defaultCacheLengthSeconds: 300 },
|
||||
(queryParams, match, sendBadge, request) => {
|
||||
++handlerCallCount
|
||||
createFakeHandlerWithCacheLength(200)(
|
||||
queryParams,
|
||||
match,
|
||||
sendBadge,
|
||||
request
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
const res = await fetch(`${baseUrl}/testing/123.json`)
|
||||
expect(res.headers.get('cache-control')).to.equal('max-age=300')
|
||||
})
|
||||
|
||||
it('should set the expires header to current time + maxAge', async function() {
|
||||
register({ cacheHeaderConfig: { defaultCacheLengthSeconds: 0 } })
|
||||
const res = await fetch(`${baseUrl}/testing/123.json?maxAge=3600`)
|
||||
|
||||
Reference in New Issue
Block a user