Skip to content

Commit

Permalink
Remove now-unused asset preservation cache v1 from Pages (#7544)
Browse files Browse the repository at this point in the history
  • Loading branch information
GregBrimble authored Dec 16, 2024
1 parent fb30983 commit 77bd9a1
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 112 deletions.
5 changes: 5 additions & 0 deletions .changeset/green-socks-trade.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cloudflare/pages-shared": patch
---

chore: Remove now-unused asset preservation cache (v1)
84 changes: 0 additions & 84 deletions packages/pages-shared/__tests__/asset-server/handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -611,90 +611,6 @@ describe("asset-server handler", () => {
}
`);
});

test("preservationCacheV1 (fallback)", async () => {
vi.setSystemTime(new Date("2024-05-09")); // 1 day before fallback is disabled

const deploymentId = "deployment-" + Math.random();
const metadata = createMetadataObject({ deploymentId }) as Metadata;
const { caches } = createCacheStorage();

const preservationCacheV1 = await caches.open("assetPreservationCache");

// Write a response to the V1 cache and make sure it persists
await preservationCacheV1.put(
"https://example.com/foo",
new Response("preserved in V1 cache!", {
headers: {
"Cache-Control": "public, max-age=300",
},
})
);

const preservationRes = await preservationCacheV1.match(
"https://example.com/foo"
);

if (!preservationRes) {
throw new Error(
"Did not match preservation cache on https://example.com/foo"
);
}

expect(await preservationRes.text()).toMatchInlineSnapshot(
`"preserved in V1 cache!"`
);

// Delete the asset from the manifest and ensure it's served from V1 preservation cache
const findAssetEntryForPath = async (_path: string) => {
return null;
};
const { response, spies } = await getTestResponse({
request: new Request("https://example.com/foo"),
metadata,
findAssetEntryForPath,
caches,
fetchAsset: () =>
Promise.resolve(Object.assign(new Response("hello world!"))),
});
expect(response.status).toBe(200);
expect(await response.text()).toMatchInlineSnapshot(
`"preserved in V1 cache!"`
);
expect(Object.fromEntries(response.headers)).toMatchInlineSnapshot(`
{
"access-control-allow-origin": "*",
"cache-control": "public, max-age=300",
"cf-cache-status": "HIT",
"content-type": "text/plain;charset=UTF-8",
"referrer-policy": "strict-origin-when-cross-origin",
"x-content-type-options": "nosniff",
}
`);
// No cache or early hints writes
expect(spies.waitUntil.length).toBe(0);

// Should disable fallback starting may 10th
vi.setSystemTime(new Date("2024-05-10"));
const { response: response2, spies: spies2 } = await getTestResponse({
request: new Request("https://example.com/foo"),
metadata,
findAssetEntryForPath,
caches,
fetchAsset: () =>
Promise.resolve(Object.assign(new Response("hello world!"))),
});
expect(response2.status).toBe(404);
expect(Object.fromEntries(response2.headers)).toMatchInlineSnapshot(`
{
"access-control-allow-origin": "*",
"cache-control": "no-store",
"referrer-policy": "strict-origin-when-cross-origin",
}
`);
// No cache or early hints writes
expect(spies2.waitUntil.length).toBe(0);
});
});

describe("isPreservationCacheResponseExpiring()", async () => {
Expand Down
38 changes: 10 additions & 28 deletions packages/pages-shared/asset-server/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,8 @@ type BodyEncoding = "manual" | "automatic";
// Before serving a 404, we check the cache to see if we've served this asset recently
// and if so, serve it from the cache instead of responding with a 404.
// This gives a bit of a grace period between deployments for any clients browsing the old deployment.
export const ASSET_PRESERVATION_CACHE_V1 = "assetPreservationCache";
// V2 stores the content hash instead of the asset.
// TODO: Remove V1 once we've fully migrated to V2
export const ASSET_PRESERVATION_CACHE_V2 = "assetPreservationCacheV2";
// Only the content hash is actually stored in the body.
export const ASSET_PRESERVATION_CACHE = "assetPreservationCacheV2";
const CACHE_CONTROL_PRESERVATION = "public, s-maxage=604800"; // 1 week

/** The preservation cache should be periodically
Expand Down Expand Up @@ -576,14 +574,14 @@ export async function generateHandler<
waitUntil(
(async () => {
try {
const assetPreservationCacheV2 = await caches.open(
ASSET_PRESERVATION_CACHE_V2
const assetPreservationCache = await caches.open(
ASSET_PRESERVATION_CACHE
);

// Check if the asset has changed since last written to cache
// or if the cached entry is getting too old and should have
// it's expiration reset.
const match = await assetPreservationCacheV2.match(request);
const match = await assetPreservationCache.match(request);
if (
!match ||
assetKey !== (await match.text()) ||
Expand All @@ -599,7 +597,7 @@ export async function generateHandler<
);
preservedResponse.headers.set("x-robots-tag", "noindex");

await assetPreservationCacheV2.put(
await assetPreservationCache.put(
request.url,
preservedResponse
);
Expand Down Expand Up @@ -637,30 +635,13 @@ export async function generateHandler<
async function notFound(): Promise<Response> {
if (caches) {
try {
const assetPreservationCacheV2 = await caches.open(
ASSET_PRESERVATION_CACHE_V2
const assetPreservationCache = await caches.open(
ASSET_PRESERVATION_CACHE
);
let preservedResponse = await assetPreservationCacheV2.match(
const preservedResponse = await assetPreservationCache.match(
request.url
);

// Continue serving from V1 preservation cache for some time to
// prevent 404s during the migration to V2
const cutoffDate = new Date("2024-05-17");
if (!preservedResponse && Date.now() < cutoffDate.getTime()) {
const assetPreservationCacheV1 = await caches.open(
ASSET_PRESERVATION_CACHE_V1
);
preservedResponse = await assetPreservationCacheV1.match(request.url);
if (preservedResponse) {
// V1 cache contains full response bodies so we return it directly
if (setMetrics) {
setMetrics({ preservationCacheResult: "checked-hit" });
}
return preservedResponse;
}
}

// V2 cache only contains the asset key, rather than the asset body:
if (preservedResponse) {
if (setMetrics) {
Expand All @@ -674,6 +655,7 @@ export async function generateHandler<
}
if (assetKey) {
const asset = await fetchAsset(assetKey);

if (asset) {
// We know the asset hasn't changed, so use the cached headers.
return new Response(asset.body, preservedResponse);
Expand Down

0 comments on commit 77bd9a1

Please sign in to comment.