From c081e78e09221f8b22d5e371f886b01943831458 Mon Sep 17 00:00:00 2001 From: mertmit Date: Mon, 19 Aug 2024 07:15:53 +0000 Subject: [PATCH] fix: memory usage for thumbnail generation --- .../thumbnail-generator.processor.ts | 89 ++++++++++--------- 1 file changed, 49 insertions(+), 40 deletions(-) diff --git a/packages/nocodb/src/modules/jobs/jobs/thumbnail-generator/thumbnail-generator.processor.ts b/packages/nocodb/src/modules/jobs/jobs/thumbnail-generator/thumbnail-generator.processor.ts index c6d41f8cb4..315e46cd81 100644 --- a/packages/nocodb/src/modules/jobs/jobs/thumbnail-generator/thumbnail-generator.processor.ts +++ b/packages/nocodb/src/modules/jobs/jobs/thumbnail-generator/thumbnail-generator.processor.ts @@ -16,17 +16,24 @@ export class ThumbnailGeneratorProcessor { async job(job: Job) { const { attachments } = job.data; - const thumbnailPromises = attachments.map(async (attachment) => { + const results = []; + + for (const attachment of attachments) { const thumbnail = await this.generateThumbnail(attachment); - return { + + if (!thumbnail) { + continue; + } + + results.push({ path: attachment.path ?? attachment.url, card_cover: thumbnail?.card_cover, small: thumbnail?.small, tiny: thumbnail?.tiny, - }; - }); + }); + } - return await Promise.all(thumbnailPromises); + return results; } private async generateThumbnail( @@ -47,6 +54,8 @@ export class ThumbnailGeneratorProcessor { return; } + sharp.concurrency(1); + try { const storageAdapter = await NcPluginMgrv2.storageAdapter(); @@ -66,42 +75,42 @@ export class ThumbnailGeneratorProcessor { tiny: path.join('nc', 'thumbnails', relativePath, 'tiny.jpg'), }; - await Promise.all( - Object.entries(thumbnailPaths).map(async ([size, thumbnailPath]) => { - let height; - switch (size) { - case 'card_cover': - height = 512; - break; - case 'small': - height = 128; - break; - case 'tiny': - height = 64; - break; - default: - height = 32; - break; - } - - const resizedImage = await sharp(file, { - limitInputPixels: false, + const sharpImage = await sharp(file, { + limitInputPixels: false, + }); + + for (const [size, thumbnailPath] of Object.entries(thumbnailPaths)) { + let height; + switch (size) { + case 'card_cover': + height = 512; + break; + case 'small': + height = 128; + break; + case 'tiny': + height = 64; + break; + default: + height = 32; + break; + } + + const resizedImage = await sharpImage + .resize(undefined, height, { + fit: sharp.fit.cover, + kernel: 'lanczos3', }) - .resize(undefined, height, { - fit: sharp.fit.cover, - kernel: 'lanczos3', - }) - .toBuffer(); - - await (storageAdapter as any).fileCreateByStream( - slash(thumbnailPath), - Readable.from(resizedImage), - { - mimetype: 'image/jpeg', - }, - ); - }), - ); + .toBuffer(); + + await (storageAdapter as any).fileCreateByStream( + slash(thumbnailPath), + Readable.from(resizedImage), + { + mimetype: 'image/jpeg', + }, + ); + } return thumbnailPaths; } catch (error) {