Skip to content

Commit

Permalink
fix: XML Malformed Error DeleteObjectsCommand (#300)
Browse files Browse the repository at this point in the history
* Double chunk DDB batch writes to not overwhelm DDB on load
  • Loading branch information
dkershner6 authored Nov 2, 2023
1 parent 438560b commit ea5e302
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 8 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ next-env.d.ts

.turbo
# Tests
tests-unit/coverage
packages/tests-unit/coverage
test-results

.sst/
Expand Down
31 changes: 24 additions & 7 deletions packages/open-next/src/adapters/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
import path from "path";

import { MAX_DYNAMO_BATCH_WRITE_ITEM_COUNT } from "./constants.js";
import { debug, error } from "./logger.js";
import { debug, error, warn } from "./logger.js";
import { chunk } from "./util.js";

interface CachedFetchValue {
Expand Down Expand Up @@ -88,7 +88,7 @@ interface CacheHandlerValue {
value: IncrementalCacheValue | null;
}

type Extension =
type CacheExtension =
| "json"
| "html"
| "rsc"
Expand All @@ -97,6 +97,13 @@ type Extension =
| "fetch"
| "redirect";

/** Beginning single backslash is intentional, to look for the dot + the extension. Do not escape it again. */
const CACHE_EXTENSION_REGEX = /\.(json|html|rsc|body|meta|fetch|redirect)$/;

export function hasCacheExtension(key: string) {
return CACHE_EXTENSION_REGEX.test(key);
}

// Expected environment variables
const {
CACHE_BUCKET_NAME,
Expand Down Expand Up @@ -459,7 +466,7 @@ export default class S3Cache {

// S3 handling

private buildS3Key(key: string, extension: Extension) {
private buildS3Key(key: string, extension: CacheExtension) {
return path.posix.join(
CACHE_BUCKET_KEY_PREFIX ?? "",
extension === "fetch" ? "__fetch" : "",
Expand All @@ -484,7 +491,11 @@ export default class S3Cache {
return (Contents ?? []).map(({ Key }) => Key) as string[];
}

private async getS3Object(key: string, extension: Extension, keys: string[]) {
private async getS3Object(
key: string,
extension: CacheExtension,
keys: string[],
) {
try {
if (!keys.includes(this.buildS3Key(key, extension)))
return { Body: null, LastModified: null };
Expand All @@ -503,7 +514,7 @@ export default class S3Cache {

private putS3Object(
key: string,
extension: Extension,
extension: CacheExtension,
value: PutObjectCommandInput["Body"],
) {
return this.client.send(
Expand All @@ -517,11 +528,17 @@ export default class S3Cache {

private async deleteS3Objects(key: string) {
try {
const regex = new RegExp(`\.(json|rsc|html|body|meta|fetch|redirect)$`);
const s3Keys = (await this.listS3Object(key)).filter(
(key) => key && regex.test(key),
(key) => key && hasCacheExtension(key),
);

if (s3Keys.length === 0) {
warn(
`No s3 keys with a valid cache extension found for ${key}, see type CacheExtension in OpenNext for details`,
);
return;
}

await this.client.send(
new DeleteObjectsCommand({
Bucket: CACHE_BUCKET_NAME,
Expand Down
11 changes: 11 additions & 0 deletions packages/tests-unit/tests/cache.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { hasCacheExtension } from "../../open-next/src/adapters/cache";

describe("hasCacheExtension", () => {
it("Should returns true if has an extension and it is a CacheExtension", () => {
expect(hasCacheExtension("hello.json")).toBeTruthy();
});

it("Should return false if does not have any extension", () => {
expect(hasCacheExtension("hello,json")).toBeFalsy();
});
});

1 comment on commit ea5e302

@vercel
Copy link

@vercel vercel bot commented on ea5e302 Nov 2, 2023

Choose a reason for hiding this comment

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

Successfully deployed to the following URLs:

open-next – ./

open-next-sst-dev.vercel.app
open-next-git-main-sst-dev.vercel.app
open-next.vercel.app

Please sign in to comment.