Skip to content

Commit

Permalink
fix(custom-resource-handlers): don't recursively process s3 bucket ob…
Browse files Browse the repository at this point in the history
…jects

I recently had the mispleasure of trying to empty a bucket with ~600000
objects using CDK's `autoDeleteObjects` feature. What I observed was
that each lambda invocation would get through a few tens of thousands of
objects in relatively good time (a few minutes), then the lambda would
grind to a halt doing very little until it reached its 15 minute
timeout. This process then repeats with subsequent invocations of the
lambda.

I suspect but have not proven that the low memory allocated to the
lambda (the default 128mb) plus this recursion is to blame. There is no
need to recurse, and doing so will put pressure on the stack, the heap,
and (because this is an async function) the event loop. I see nothing
else that could result in such an outcome here.
  • Loading branch information
isker committed May 15, 2024
1 parent 4b6dc8c commit 134821c
Showing 1 changed file with 11 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -70,23 +70,22 @@ async function denyWrites(bucketName: string) {
}

/**
* Recursively delete all items in the bucket
* Iteratively delete all items in the bucket
*
* @param bucketName the bucket name
*/
async function emptyBucket(bucketName: string) {
const listedObjects = await s3.listObjectVersions({ Bucket: bucketName });
const contents = [...listedObjects.Versions ?? [], ...listedObjects.DeleteMarkers ?? []];
if (contents.length === 0) {
return;
}

const records = contents.map((record: any) => ({ Key: record.Key, VersionId: record.VersionId }));
await s3.deleteObjects({ Bucket: bucketName, Delete: { Objects: records } });
let listedObjects;
do {
listedObjects = await s3.listObjectVersions({ Bucket: bucketName });
const contents = [...listedObjects.Versions ?? [], ...listedObjects.DeleteMarkers ?? []];
if (contents.length === 0) {
return;
}

if (listedObjects?.IsTruncated) {
await emptyBucket(bucketName);
}
const records = contents.map((record) => ({ Key: record.Key, VersionId: record.VersionId }));
await s3.deleteObjects({ Bucket: bucketName, Delete: { Objects: records } });
} while (listedObjects?.IsTruncated)
}

async function onDelete(bucketName?: string) {
Expand Down

0 comments on commit 134821c

Please sign in to comment.