UNPKG

cdk-nextjs

Version:

Deploy Next.js apps on AWS with CDK

101 lines 15.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.pruneS3 = pruneS3; // eslint-disable-next-line import/no-extraneous-dependencies const client_s3_1 = require("@aws-sdk/client-s3"); const utils_1 = require("../utils"); const s3Client = new client_s3_1.S3Client(); // Maximum number of concurrent operations const MAX_CONCURRENT_OPERATIONS = 50; /** * Given `bucketName`, `currentBuildId`, and `msTtl`, list all objects * in the bucket and delete any that 1/ do not have a metadata key of "next-build-id" * and value of `currentBuildId` and 2/ were created more than `msTtl` ago */ async function pruneS3(props) { const { bucketName, currentBuildId, msTtl } = props; const cutoffDate = new Date(Date.now() - msTtl); const objectsToDelete = []; let continuationToken = undefined; let listObjectsCount = 0; do { // List objects in the bucket const listObjectsV2Input = { Bucket: bucketName, ContinuationToken: continuationToken, }; const listResponse = await s3Client.send(new client_s3_1.ListObjectsV2Command(listObjectsV2Input)); if (!listResponse.Contents || listResponse.Contents.length === 0) { break; } // Filter out objects without keys const oldObjects = listResponse.Contents.filter((obj) => { const lastModified = obj.LastModified || new Date(); return obj.Key && lastModified < cutoffDate; }); (0, utils_1.debug)(`Checking old objects metadata to determine pruning: ${oldObjects.map((o) => o.Key)}`); // Process objects in parallel with controlled concurrency const checkResults = await processBatch(oldObjects, MAX_CONCURRENT_OPERATIONS, async (object) => { if (!object.Key) return null; try { const headResponse = await s3Client.send(new client_s3_1.HeadObjectCommand({ Bucket: bucketName, Key: object.Key, })); const objectBuildId = headResponse.Metadata?.["next-build-id"]; // Return the key if it should be deleted if (objectBuildId !== currentBuildId) { return { Key: object.Key }; } } catch (error) { console.error(`Error checking object ${object.Key}:`, error); } return null; }); // Add valid objects to delete list objectsToDelete.push(...checkResults.filter(Boolean)); if (listResponse.NextContinuationToken) { continuationToken = listResponse.NextContinuationToken; } listObjectsCount++; // assume less than 100K objects (100 * 1K objects per ListObjectsV2Command = 100K) } while (continuationToken && listObjectsCount <= 100); // Delete objects in parallel batches (respecting S3's 1000 objects per request limit) if (objectsToDelete.length > 0) { const deleteBatches = []; for (let i = 0; i < objectsToDelete.length; i += 1000) { const batch = objectsToDelete.slice(i, i + 1000); deleteBatches.push(batch); } await processBatch(deleteBatches, 5, // Process up to 5 delete batches in parallel async (batch) => { try { (0, utils_1.debug)(`Deleting objects: ${batch.map((b) => b.Key)} from ${bucketName}`); await s3Client.send(new client_s3_1.DeleteObjectsCommand({ Bucket: bucketName, Delete: { Objects: batch }, })); (0, utils_1.debug)(`Deleted ${batch.length} objects from ${bucketName}`); } catch (error) { console.error("Error deleting objects:", error); } }); } (0, utils_1.debug)(`Pruning complete. Deleted ${objectsToDelete.length} objects from ${bucketName}`); } /** * Process objects in batches to avoid overwhelming the system */ async function processBatch(items, batchSize, processFn) { const results = []; for (let i = 0; i < items.length; i += batchSize) { const batch = items.slice(i, i + batchSize); const batchResults = await Promise.all(batch.map(processFn)); results.push(...batchResults); } return results; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJ1bmUtczMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGFtYmRhcy9wb3N0LWRlcGxveS9wcnVuZS1zMy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQTRCQSwwQkEyR0M7QUF2SUQsNkRBQTZEO0FBQzdELGtEQU00QjtBQUM1QixvQ0FBaUM7QUFFakMsTUFBTSxRQUFRLEdBQUcsSUFBSSxvQkFBUSxFQUFFLENBQUM7QUFDaEMsMENBQTBDO0FBQzFDLE1BQU0seUJBQXlCLEdBQUcsRUFBRSxDQUFDO0FBV3JDOzs7O0dBSUc7QUFDSSxLQUFLLFVBQVUsT0FBTyxDQUFDLEtBQW1CO0lBQy9DLE1BQU0sRUFBRSxVQUFVLEVBQUUsY0FBYyxFQUFFLEtBQUssRUFBRSxHQUFHLEtBQUssQ0FBQztJQUVwRCxNQUFNLFVBQVUsR0FBRyxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsS0FBSyxDQUFDLENBQUM7SUFDaEQsTUFBTSxlQUFlLEdBQXNCLEVBQUUsQ0FBQztJQUU5QyxJQUFJLGlCQUFpQixHQUF1QixTQUFTLENBQUM7SUFDdEQsSUFBSSxnQkFBZ0IsR0FBRyxDQUFDLENBQUM7SUFFekIsR0FBRyxDQUFDO1FBQ0YsNkJBQTZCO1FBQzdCLE1BQU0sa0JBQWtCLEdBQThCO1lBQ3BELE1BQU0sRUFBRSxVQUFVO1lBQ2xCLGlCQUFpQixFQUFFLGlCQUFpQjtTQUNyQyxDQUFDO1FBQ0YsTUFBTSxZQUFZLEdBQUcsTUFBTSxRQUFRLENBQUMsSUFBSSxDQUN0QyxJQUFJLGdDQUFvQixDQUFDLGtCQUFrQixDQUFDLENBQzdDLENBQUM7UUFFRixJQUFJLENBQUMsWUFBWSxDQUFDLFFBQVEsSUFBSSxZQUFZLENBQUMsUUFBUSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUNqRSxNQUFNO1FBQ1IsQ0FBQztRQUVELGtDQUFrQztRQUNsQyxNQUFNLFVBQVUsR0FBRyxZQUFZLENBQUMsUUFBUSxD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QUssRUFBRTtpQkFDM0IsQ0FBQyxDQUNILENBQUM7Z0JBQ0YsSUFBQSxhQUFLLEVBQUMsV0FBVyxLQUFLLENBQUMsTUFBTSxpQkFBaUIsVUFBVSxFQUFFLENBQUMsQ0FBQztZQUM5RCxDQUFDO1lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztnQkFDZixPQUFPLENBQUMsS0FBSyxDQUFDLHlCQUF5QixFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQ2xELENBQUM7UUFDSCxDQUFDLENBQ0YsQ0FBQztJQUNKLENBQUM7SUFFRCxJQUFBLGFBQUssRUFDSCw2QkFBNkIsZUFBZSxDQUFDLE1BQU0saUJBQWlCLFVBQVUsRUFBRSxDQUNqRixDQUFDO0FBQ0osQ0FBQztBQUVEOztHQUVHO0FBQ0gsS0FBSyxVQUFVLFlBQVksQ0FDekIsS0FBVSxFQUNWLFNBQWlCLEVBQ2pCLFNBQWtDO0lBRWxDLE1BQU0sT0FBTyxHQUFRLEVBQUUsQ0FBQztJQUV4QixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDLElBQUksU0FBUyxFQUFFLENBQUM7UUFDakQsTUFBTSxLQUFLLEdBQUcsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQyxHQUFHLFNBQVMsQ0FBQyxDQUFDO1FBQzVDLE1BQU0sWUFBWSxHQUFHLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUM7UUFDN0QsT0FBTyxDQUFDLElBQUksQ0FBQyxHQUFHLFlBQVksQ0FBQyxDQUFDO0lBQ2hDLENBQUM7SUFFRCxPQUFPLE9BQU8sQ0FBQztBQUNqQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1leHRyYW5lb3VzLWRlcGVuZGVuY2llc1xuaW1wb3J0IHtcbiAgUzNDbGllbnQsXG4gIExpc3RPYmplY3RzVjJDb21tYW5kLFxuICBEZWxldGVPYmplY3RzQ29tbWFuZCxcbiAgSGVhZE9iamVjdENvbW1hbmQsXG4gIExpc3RPYmplY3RzVjJDb21tYW5kSW5wdXQsXG59IGZyb20gXCJAYXdzLXNkay9jbGllbnQtczNcIjtcbmltcG9ydCB7IGRlYnVnIH0gZnJvbSBcIi4uL3V0aWxzXCI7XG5cbmNvbnN0IHMzQ2xpZW50ID0gbmV3IFMzQ2xpZW50KCk7XG4vLyBNYXhpbXVtIG51bWJlciBvZiBjb25jdXJyZW50IG9wZXJhdGlvbnNcbmNvbnN0IE1BWF9DT05DVVJSRU5UX09QRVJBVElPTlMgPSA1MDtcblxuaW50ZXJmYWNlIFBydW5lUzNQcm9wcyB7XG4gIGJ1Y2tldE5hbWU6IHN0cmluZztcbiAgY3VycmVudEJ1aWxkSWQ6IHN0cmluZztcbiAgLyoqXG4gICAqIFRpbWUgdG8gbGl2ZSBpbiBtaWxsaXNlY29uZHMuXG4gICAqL1xuICBtc1R0bDogbnVtYmVyO1xufVxuXG4vKipcbiAqIEdpdmVuIGBidWNrZXROYW1lYCwgYGN1cnJlbnRCdWlsZElkYCwgYW5kIGBtc1R0bGAsIGxpc3QgYWxsIG9iamVjdHNcbiAqIGluIHRoZSBidWNrZXQgYW5kIGRlbGV0ZSBhbnkgdGhhdCAxLyBkbyBub3QgaGF2ZSBhIG1ldGFkYXRhIGtleSBvZiBcIm5leHQtYnVpbGQtaWRcIlxuICogYW5kIHZhbHVlIG9mIGBjdXJyZW50QnVpbGRJZGAgYW5kIDIvIHdlcmUgY3JlYXRlZCBtb3JlIHRoYW4gYG1zVHRsYCBhZ29cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHBydW5lUzMocHJvcHM6IFBydW5lUzNQcm9wcykge1xuICBjb25zdCB7IGJ1Y2tldE5hbWUsIGN1cnJlbnRCdWlsZElkLCBtc1R0bCB9ID0gcHJvcHM7XG5cbiAgY29uc3QgY3V0b2ZmRGF0ZSA9IG5ldyBEYXRlKERhdGUubm93KCkgLSBtc1R0bCk7XG4gIGNvbnN0IG9iamVjdHNUb0RlbGV0ZTogeyBLZXk6IHN0cmluZyB9W10gPSBbXTtcblxuICBsZXQgY29udGludWF0aW9uVG9rZW46IHN0cmluZyB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZDtcbiAgbGV0IGxpc3RPYmplY3RzQ291bnQgPSAwO1xuXG4gIGRvIHtcbiAgICAvLyBMaXN0IG9iamVjdHMgaW4gdGhlIGJ1Y2tldFxuICAgIGNvbnN0IGxpc3RPYmplY3RzVjJJbnB1dDogTGlzdE9iamVjdHNWMkNvbW1hbmRJbnB1dCA9IHtcbiAgICAgIEJ1Y2tldDogYnVja2V0TmFtZSxcbiAgICAgIENvbnRpbnVhdGlvblRva2VuOiBjb250aW51YXRpb25Ub2tlbixcbiAgICB9O1xuICAgIGNvbnN0IGxpc3RSZXNwb25zZSA9IGF3YWl0IHMzQ2xpZW50LnNlbmQoXG4gICAgICBuZXcgTGlzdE9iamVjdHNWMkNvbW1hbmQobGlzdE9iamVjdHNWMklucHV0KSxcbiAgICApO1xuXG4gICAgaWYgKCFsaXN0UmVzcG9uc2UuQ29udGVudHMgfHwgbGlzdFJlc3BvbnNlLkNvbnRlbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgYnJlYWs7XG4gICAgfVxuXG4gICAgLy8gRmlsdGVyIG91dCBvYmplY3RzIHdpdGhvdXQga2V5c1xuICAgIGNvbnN0IG9sZE9iamVjdHMgPSBsaXN0UmVzcG9uc2UuQ29udGVudHMuZmlsdGVyKChvYmopID0+IHtcbiAgICAgIGNvbnN0IGxhc3RNb2RpZmllZCA9IG9iai5MYXN0TW9kaWZpZWQgfHwgbmV3IERhdGUoKTtcbiAgICAgIHJldHVybiBvYmouS2V5ICYmIGxhc3RNb2RpZmllZCA8IGN1dG9mZkRhdGU7XG4gICAgfSk7XG4gICAgZGVidWcoXG4gICAgICBgQ2hlY2tpbmcgb2xkIG9iamVjdHMgbWV0YWRhdGEgdG8gZGV0ZXJtaW5lIHBydW5pbmc6ICR7b2xkT2JqZWN0cy5tYXAoKG8pID0+IG8uS2V5KX1gLFxuICAgICk7XG5cbiAgICAvLyBQcm9jZXNzIG9iamVjdHMgaW4gcGFyYWxsZWwgd2l0aCBjb250cm9sbGVkIGNvbmN1cnJlbmN5XG4gICAgY29uc3QgY2hlY2tSZXN1bHRzID0gYXdhaXQgcHJvY2Vzc0JhdGNoKFxuICAgICAgb2xkT2JqZWN0cyxcbiAgICAgIE1BWF9DT05DVVJSRU5UX09QRVJBVElPTlMsXG4gICAgICBhc3luYyAob2JqZWN0KSA9PiB7XG4gICAgICAgIGlmICghb2JqZWN0LktleSkgcmV0dXJuIG51bGw7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBjb25zdCBoZWFkUmVzcG9uc2UgPSBhd2FpdCBzM0NsaWVudC5zZW5kKFxuICAgICAgICAgICAgbmV3IEhlYWRPYmplY3RDb21tYW5kKHtcbiAgICAgICAgICAgICAgQnVja2V0OiBidWNrZXROYW1lLFxuICAgICAgICAgICAgICBLZXk6IG9iamVjdC5LZXksXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICApO1xuXG4gICAgICAgICAgY29uc3Qgb2JqZWN0QnVpbGRJZCA9IGhlYWRSZXNwb25zZS5NZXRhZGF0YT8uW1wibmV4dC1idWlsZC1pZFwiXTtcblxuICAgICAgICAgIC8vIFJldHVybiB0aGUga2V5IGlmIGl0IHNob3VsZCBiZSBkZWxldGVkXG4gICAgICAgICAgaWYgKG9iamVjdEJ1aWxkSWQgIT09IGN1cnJlbnRCdWlsZElkKSB7XG4gICAgICAgICAgICByZXR1cm4geyBLZXk6IG9iamVjdC5LZXkgfTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihgRXJyb3IgY2hlY2tpbmcgb2JqZWN0ICR7b2JqZWN0LktleX06YCwgZXJyb3IpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9LFxuICAgICk7XG5cbiAgICAvLyBBZGQgdmFsaWQgb2JqZWN0cyB0byBkZWxldGUgbGlzdFxuICAgIG9iamVjdHNUb0RlbGV0ZS5wdXNoKFxuICAgICAgLi4uKGNoZWNrUmVzdWx0cy5maWx0ZXIoQm9vbGVhbikgYXMgeyBLZXk6IHN0cmluZyB9W10pLFxuICAgICk7XG5cbiAgICBpZiAobGlzdFJlc3BvbnNlLk5leHRDb250aW51YXRpb25Ub2tlbikge1xuICAgICAgY29udGludWF0aW9uVG9rZW4gPSBsaXN0UmVzcG9uc2UuTmV4dENvbnRpbnVhdGlvblRva2VuO1xuICAgIH1cbiAgICBsaXN0T2JqZWN0c0NvdW50Kys7XG4gICAgLy8gYXNzdW1lIGxlc3MgdGhhbiAxMDBLIG9iamVjdHMgKDEwMCAqIDFLIG9iamVjdHMgcGVyIExpc3RPYmplY3RzVjJDb21tYW5kID0gMTAwSylcbiAgfSB3aGlsZSAoY29udGludWF0aW9uVG9rZW4gJiYgbGlzdE9iamVjdHNDb3VudCA8PSAxMDApO1xuXG4gIC8vIERlbGV0ZSBvYmplY3RzIGluIHBhcmFsbGVsIGJhdGNoZXMgKHJlc3BlY3RpbmcgUzMncyAxMDAwIG9iamVjdHMgcGVyIHJlcXVlc3QgbGltaXQpXG4gIGlmIChvYmplY3RzVG9EZWxldGUubGVuZ3RoID4gMCkge1xuICAgIGNvbnN0IGRlbGV0ZUJhdGNoZXMgPSBbXTtcblxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgb2JqZWN0c1RvRGVsZXRlLmxlbmd0aDsgaSArPSAxMDAwKSB7XG4gICAgICBjb25zdCBiYXRjaCA9IG9iamVjdHNUb0RlbGV0ZS5zbGljZShpLCBpICsgMTAwMCk7XG4gICAgICBkZWxldGVCYXRjaGVzLnB1c2goYmF0Y2gpO1xuICAgIH1cblxuICAgIGF3YWl0IHByb2Nlc3NCYXRjaChcbiAgICAgIGRlbGV0ZUJhdGNoZXMsXG4gICAgICA1LCAvLyBQcm9jZXNzIHVwIHRvIDUgZGVsZXRlIGJhdGNoZXMgaW4gcGFyYWxsZWxcbiAgICAgIGFzeW5jIChiYXRjaCkgPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGRlYnVnKFxuICAgICAgICAgICAgYERlbGV0aW5nIG9iamVjdHM6ICR7YmF0Y2gubWFwKChiKSA9PiBiLktleSl9IGZyb20gJHtidWNrZXROYW1lfWAsXG4gICAgICAgICAgKTtcbiAgICAgICAgICBhd2FpdCBzM0NsaWVudC5zZW5kKFxuICAgICAgICAgICAgbmV3IERlbGV0ZU9iamVjdHNDb21tYW5kKHtcbiAgICAgICAgICAgICAgQnVja2V0OiBidWNrZXROYW1lLFxuICAgICAgICAgICAgICBEZWxldGU6IHsgT2JqZWN0czogYmF0Y2ggfSxcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgICk7XG4gICAgICAgICAgZGVidWcoYERlbGV0ZWQgJHtiYXRjaC5sZW5ndGh9IG9iamVjdHMgZnJvbSAke2J1Y2tldE5hbWV9YCk7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihcIkVycm9yIGRlbGV0aW5nIG9iamVjdHM6XCIsIGVycm9yKTtcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICApO1xuICB9XG5cbiAgZGVidWcoXG4gICAgYFBydW5pbmcgY29tcGxldGUuIERlbGV0ZWQgJHtvYmplY3RzVG9EZWxldGUubGVuZ3RofSBvYmplY3RzIGZyb20gJHtidWNrZXROYW1lfWAsXG4gICk7XG59XG5cbi8qKlxuICogUHJvY2VzcyBvYmplY3RzIGluIGJhdGNoZXMgdG8gYXZvaWQgb3ZlcndoZWxtaW5nIHRoZSBzeXN0ZW1cbiAqL1xuYXN5bmMgZnVuY3Rpb24gcHJvY2Vzc0JhdGNoPFQsIFI+KFxuICBpdGVtczogVFtdLFxuICBiYXRjaFNpemU6IG51bWJlcixcbiAgcHJvY2Vzc0ZuOiAoaXRlbTogVCkgPT4gUHJvbWlzZTxSPixcbik6IFByb21pc2U8UltdPiB7XG4gIGNvbnN0IHJlc3VsdHM6IFJbXSA9IFtdO1xuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgaXRlbXMubGVuZ3RoOyBpICs9IGJhdGNoU2l6ZSkge1xuICAgIGNvbnN0IGJhdGNoID0gaXRlbXMuc2xpY2UoaSwgaSArIGJhdGNoU2l6ZSk7XG4gICAgY29uc3QgYmF0Y2hSZXN1bHRzID0gYXdhaXQgUHJvbWlzZS5hbGwoYmF0Y2gubWFwKHByb2Nlc3NGbikpO1xuICAgIHJlc3VsdHMucHVzaCguLi5iYXRjaFJlc3VsdHMpO1xuICB9XG5cbiAgcmV0dXJuIHJlc3VsdHM7XG59XG4iXX0=