Skip to content

Commit 22e8f70

Browse files
conico974fwang
andauthored
Fix isr not found (#141)
* fix: handle not-found page for isr * fix: handle redirect in cache * remove console.log * Sync --------- Co-authored-by: Frank <[email protected]>
1 parent 8db7e07 commit 22e8f70

File tree

2 files changed

+71
-8
lines changed

2 files changed

+71
-8
lines changed

.changeset/fast-kangaroos-hang.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"open-next": patch
3+
---
4+
5+
ISR: support "notFound" and "redirect" in getStaticProps

packages/open-next/src/adapters/cache.ts

Lines changed: 66 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ import {
22
S3Client,
33
GetObjectCommand,
44
PutObjectCommand,
5+
DeleteObjectsCommand,
56
PutObjectCommandInput,
67
ListObjectsV2Command,
78
} from "@aws-sdk/client-s3";
89
import path from "node:path";
9-
import { error, awsLogger } from "./logger.js";
10+
import { awsLogger, debug, error } from "./logger.js";
1011
import { loadBuildId } from "./util.js";
1112

1213
interface CachedFetchValue {
@@ -75,7 +76,14 @@ interface CacheHandlerValue {
7576
value: IncrementalCacheValue | null;
7677
}
7778

78-
type Extension = "json" | "html" | "rsc" | "body" | "meta" | "fetch";
79+
type Extension =
80+
| "json"
81+
| "html"
82+
| "rsc"
83+
| "body"
84+
| "meta"
85+
| "fetch"
86+
| "redirect";
7987

8088
// Expected environment variables
8189
const { CACHE_BUCKET_NAME, CACHE_BUCKET_KEY_PREFIX, CACHE_BUCKET_REGION } =
@@ -100,6 +108,7 @@ export default class S3Cache {
100108
}
101109

102110
async getFetchCache(key: string) {
111+
debug("get fetch cache", { key });
103112
try {
104113
const { Body, LastModified } = await this.getS3Object(key, "fetch");
105114
return {
@@ -113,10 +122,12 @@ export default class S3Cache {
113122
}
114123

115124
async getIncrementalCache(key: string): Promise<CacheHandlerValue | null> {
116-
const { Contents } = await this.listS3Objects(key);
117-
const keys = (Contents ?? []).map(({ Key }) => Key);
125+
const keys = await this.listS3Object(key);
126+
if (keys.length === 0) return null;
127+
debug("keys", keys);
118128

119129
if (keys.includes(this.buildS3Key(key, "body"))) {
130+
debug("get body cache ", { key });
120131
try {
121132
const [{ Body, LastModified }, { Body: MetaBody }] = await Promise.all([
122133
this.getS3Object(key, "body"),
@@ -143,6 +154,7 @@ export default class S3Cache {
143154
if (keys.includes(this.buildS3Key(key, "html"))) {
144155
const isJson = keys.includes(this.buildS3Key(key, "json"));
145156
const isRsc = keys.includes(this.buildS3Key(key, "rsc"));
157+
debug("get html cache ", { key, isJson, isRsc });
146158
if (!isJson && !isRsc) return null;
147159

148160
try {
@@ -166,10 +178,27 @@ export default class S3Cache {
166178
}
167179
return null;
168180
}
181+
182+
// Check for redirect last. This way if a page has been regenerated
183+
// after having been redirected, we'll get the page data
184+
if (keys.includes(this.buildS3Key(key, "redirect"))) {
185+
debug("get redirect cache", { key });
186+
try {
187+
const { Body, LastModified } = await this.getS3Object(key, "redirect");
188+
return {
189+
lastModified: LastModified?.getTime(),
190+
value: JSON.parse((await Body?.transformToString()) ?? "{}"),
191+
};
192+
} catch (e) {
193+
error("Failed to get redirect cache", e);
194+
}
195+
return null;
196+
}
197+
169198
return null;
170199
}
171200

172-
async set(key: string, data?: IncrementalCacheValue): Promise<void> {
201+
async set(key: string, data?: IncrementalCacheValue | null): Promise<void> {
173202
if (data?.kind === "ROUTE") {
174203
const { body, status, headers } = data;
175204
await Promise.all([
@@ -189,6 +218,12 @@ export default class S3Cache {
189218
]);
190219
} else if (data?.kind === "FETCH") {
191220
await this.putS3Object(key, "fetch", JSON.stringify(data));
221+
} else if (data?.kind === "REDIRECT") {
222+
// delete potential page data if we're redirecting
223+
await this.deleteS3Objects(key);
224+
await this.putS3Object(key, "redirect", JSON.stringify(data));
225+
} else if (data === null || data === undefined) {
226+
await this.deleteS3Objects(key);
192227
}
193228
}
194229

@@ -205,13 +240,16 @@ export default class S3Cache {
205240
return path.posix.join(CACHE_BUCKET_KEY_PREFIX ?? "", this.buildId, key);
206241
}
207242

208-
private listS3Objects(key: string) {
209-
return this.client.send(
243+
private async listS3Object(key: string) {
244+
const { Contents } = await this.client.send(
210245
new ListObjectsV2Command({
211246
Bucket: CACHE_BUCKET_NAME,
212-
Prefix: this.buildS3KeyPrefix(key),
247+
// add a point to the key so that it only matches the key and
248+
// not other keys starting with the same string
249+
Prefix: `${this.buildS3KeyPrefix(key)}.`,
213250
})
214251
);
252+
return (Contents ?? []).map(({ Key }) => Key);
215253
}
216254

217255
private getS3Object(key: string, extension: Extension) {
@@ -236,4 +274,24 @@ export default class S3Cache {
236274
})
237275
);
238276
}
277+
278+
private async deleteS3Objects(key: string) {
279+
try {
280+
const regex = new RegExp(`\.(json|rsc|html|body|meta|fetch|redirect)$`);
281+
const s3Keys = (await this.listS3Object(key)).filter(
282+
(key) => key && regex.test(key)
283+
);
284+
285+
await this.client.send(
286+
new DeleteObjectsCommand({
287+
Bucket: CACHE_BUCKET_NAME,
288+
Delete: {
289+
Objects: s3Keys.map((Key) => ({ Key })),
290+
},
291+
})
292+
);
293+
} catch (e) {
294+
error("Failed to delete cache", e);
295+
}
296+
}
239297
}

0 commit comments

Comments
 (0)