From a98bb74929837147aaf9e1270734da9e7b449696 Mon Sep 17 00:00:00 2001 From: iotserver24 <147928812+iotserver24@users.noreply.github.com> Date: Sat, 16 May 2026 16:44:04 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=20Bolt:=20Chunked=20concurrency=20for?= =?UTF-8?q?=20file=20history=20to=20prevent=20EMFILE=20errors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/src/file-history.ts | 82 +++++++++++++++++-------------- 1 file changed, 45 insertions(+), 37 deletions(-) diff --git a/packages/core/src/file-history.ts b/packages/core/src/file-history.ts index 1abdda2..2a5717d 100644 --- a/packages/core/src/file-history.ts +++ b/packages/core/src/file-history.ts @@ -193,43 +193,51 @@ export async function fileHistoryMakeSnapshot( const mostRecentSnapshot = captured.snapshots.at(-1); if (mostRecentSnapshot) { - await Promise.all( - Array.from(captured.trackedFiles, async (trackingPath) => { - const latestBackup = mostRecentSnapshot.trackedFileBackups[trackingPath]; - const nextVersion = latestBackup ? latestBackup.version + 1 : 1; - - let fileStats: Stats | undefined; - try { - fileStats = await stat(trackingPath); - } catch { - fileStats = undefined; - } - - if (!fileStats) { - trackedFileBackups[trackingPath] = { - backupFileName: null, - version: nextVersion, - backupTime: new Date().toISOString(), - }; - return; - } - - if ( - latestBackup && - latestBackup.backupFileName !== null && - !(await checkOriginFileChanged( - trackingPath, - latestBackup.backupFileName, - fileStats, - )) - ) { - trackedFileBackups[trackingPath] = latestBackup; - return; - } - - trackedFileBackups[trackingPath] = await createBackup(trackingPath, nextVersion); - }), - ); + const trackedFilesArray = Array.from(captured.trackedFiles); + // ⚡ Bolt: Chunked concurrency to prevent EMFILE (too many open files) OS errors when evaluating thousands of tracked files. + const CONCURRENCY_LIMIT = 20; + + for (let i = 0; i < trackedFilesArray.length; i += CONCURRENCY_LIMIT) { + const chunk = trackedFilesArray.slice(i, i + CONCURRENCY_LIMIT); + + await Promise.all( + chunk.map(async (trackingPath) => { + const latestBackup = mostRecentSnapshot.trackedFileBackups[trackingPath]; + const nextVersion = latestBackup ? latestBackup.version + 1 : 1; + + let fileStats: Stats | undefined; + try { + fileStats = await stat(trackingPath); + } catch { + fileStats = undefined; + } + + if (!fileStats) { + trackedFileBackups[trackingPath] = { + backupFileName: null, + version: nextVersion, + backupTime: new Date().toISOString(), + }; + return; + } + + if ( + latestBackup && + latestBackup.backupFileName !== null && + !(await checkOriginFileChanged( + trackingPath, + latestBackup.backupFileName, + fileStats, + )) + ) { + trackedFileBackups[trackingPath] = latestBackup; + return; + } + + trackedFileBackups[trackingPath] = await createBackup(trackingPath, nextVersion); + }) + ); + } } let createdSnapshot: FileHistorySnapshot | undefined;