diff --git a/lib/upload-manager.js b/lib/upload-manager.js index 220a249..f08210f 100644 --- a/lib/upload-manager.js +++ b/lib/upload-manager.js @@ -310,18 +310,30 @@ class UploadManager extends EventEmitter { this._batchResults = results; this._additionalPromises = []; // Track jobs added mid-batch via addJobs() - for (const task of tasks) { - const fileName = path.basename(task.file); - if (!results.has(task.file)) { - let size = 0; - try { size = fs.statSync(task.file).size; } catch {} - results.set(task.file, { name: fileName, size, results: [] }); + const DEDUP_CHUNK = 200; + for (let i = 0; i < tasks.length; i += DEDUP_CHUNK) { + const end = Math.min(i + DEDUP_CHUNK, tasks.length); + for (let j = i; j < end; j++) { + const task = tasks[j]; + if (!results.has(task.file)) { + const fileName = path.basename(task.file); + let size = 0; + try { size = fs.statSync(task.file).size; } catch {} + results.set(task.file, { name: fileName, size, results: [] }); + } } + if (end < tasks.length) await new Promise(setImmediate); } this._startStatsTimer(); - const promises = tasks.map((task) => this._runJob(task, results, signal)); + const SPAWN_CHUNK = 100; + const promises = []; + for (let i = 0; i < tasks.length; i += SPAWN_CHUNK) { + const end = Math.min(i + SPAWN_CHUNK, tasks.length); + for (let j = i; j < end; j++) promises.push(this._runJob(tasks[j], results, signal)); + if (end < tasks.length) await new Promise(setImmediate); + } await Promise.allSettled(promises); // Wait for any jobs added mid-batch via addJobs() while (this._additionalPromises.length > 0) { diff --git a/main.js b/main.js index b5448da..957b81c 100644 --- a/main.js +++ b/main.js @@ -216,23 +216,10 @@ function rotLog(msg, ts) { try { const iso = new Date(ts || Date.now()).toISOString(); const line = `[${iso}] ${msg}\n`; - // Write synchronously. Rotation events are rare (a handful per batch) so - // the batching optimization from debugLog doesn't buy us anything, and - // syncing guarantees the user can refresh the file and see fresh entries - // without waiting on a flush timer. - const candidates = [ - getRotLogPath(), - path.join(app.getPath('desktop') || app.getPath('userData'), 'account-rotation.log'), - path.join(app.getPath('userData'), 'account-rotation.log') - ]; - for (const target of candidates) { - try { - fs.mkdirSync(path.dirname(target), { recursive: true }); - fs.appendFileSync(target, line, 'utf-8'); - break; - } catch {} + _rotLogBuffer.push(line); + if (!_rotLogFlushTimer) { + _rotLogFlushTimer = setTimeout(() => { _rotLogFlushTimer = null; _flushRotLog(); }, 500); } - // Mirror into the main debug log for single-file-grep convenience. _debugLogBuffer.push(`[${iso}] [ROT] ${msg}\n`); if (!_debugLogFlushTimer) { _debugLogFlushTimer = setTimeout(() => { _debugLogFlushTimer = null; _flushDebugLog(); }, 500);