fix(perf): freeze on Start with 2000+ jobs — gate probe + rot-log behind semaphore

This commit is contained in:
Administrator 2026-06-07 20:40:55 +02:00
parent b0b86e5016
commit d280765feb
2 changed files with 25 additions and 12 deletions

View File

@ -9,7 +9,7 @@ const DoodstreamUploader = require('./doodstream-upload');
const ClouddropUploader = require('./clouddrop-upload'); const ClouddropUploader = require('./clouddrop-upload');
const Semaphore = require('./semaphore'); const Semaphore = require('./semaphore');
const Throttle = require('./throttle'); const Throttle = require('./throttle');
const { probeFileHead, summarizeFileStat } = require('./file-probe'); const { probeFileHead } = require('./file-probe');
const DEFAULT_SETTINGS = { const DEFAULT_SETTINGS = {
retries: 3, retries: 3,
@ -435,21 +435,25 @@ class UploadManager extends EventEmitter {
maxAttempts maxAttempts
}); });
const fileStat = summarizeFileStat(task.file);
const fileProbe = await probeFileHead(task.file, 64).catch((err) => ({ ok: false, error: err.message, kind: 'unreadable' }));
this._rotLog('upload-start', {
jobId, hoster: task.hoster, accountId: task.accountId, fileName,
fileSize: fileStat.size, fileMtime: fileStat.mtime,
detectedKind: fileProbe && fileProbe.kind ? fileProbe.kind : 'unknown',
isVideoLike: !!(fileProbe && fileProbe.isVideoLike),
headHex: fileProbe && fileProbe.headHex ? fileProbe.headHex.slice(0, 32) : null
});
// Acquire hoster semaphore first so jobs waiting for a hoster slot // Acquire hoster semaphore first so jobs waiting for a hoster slot
// don't waste global slots (prevents underutilization) // don't waste global slots (prevents underutilization)
await hosterSemaphore.acquire(signal); await hosterSemaphore.acquire(signal);
hosterSlotAcquired = true; hosterSlotAcquired = true;
let fileProbe = null;
try {
fileProbe = await probeFileHead(task.file, 64);
} catch (err) {
fileProbe = { ok: false, error: err && err.message, kind: 'unreadable' };
}
this._rotLog('upload-start', {
jobId, hoster: task.hoster, accountId: task.accountId, fileName,
fileSize,
detectedKind: fileProbe && fileProbe.kind ? fileProbe.kind : 'unknown',
isVideoLike: !!(fileProbe && fileProbe.isVideoLike),
headHex: fileProbe && fileProbe.headHex ? fileProbe.headHex.slice(0, 32) : null
});
if (globalSemaphore) { if (globalSemaphore) {
await globalSemaphore.acquire(signal); await globalSemaphore.acquire(signal);
globalSlotAcquired = true; globalSlotAcquired = true;

11
main.js
View File

@ -1445,6 +1445,15 @@ ipcMain.handle('start-upload', (_event, payload) => {
} }
}); });
const ROT_LOG_RENDERER_EVENTS = new Set([
'switchAccount',
'pre-job-swap',
'try-alternate-after-fail',
'mark-failed',
'rotation-end',
'doodstream-via-api',
'doodstream-via-web'
]);
uploadManager.on('rot-log', (entry) => { uploadManager.on('rot-log', (entry) => {
const { ts, event, ...rest } = entry; const { ts, event, ...rest } = entry;
const pairs = Object.entries(rest) const pairs = Object.entries(rest)
@ -1454,7 +1463,7 @@ ipcMain.handle('start-upload', (_event, payload) => {
if (entry.jobId) { if (entry.jobId) {
_appendJobLog(entry.jobId, { ts: ts || Date.now(), kind: 'rot', event, ...rest }); _appendJobLog(entry.jobId, { ts: ts || Date.now(), kind: 'rot', event, ...rest });
} }
if (mainWindow && !mainWindow.isDestroyed()) { if (mainWindow && !mainWindow.isDestroyed() && ROT_LOG_RENDERER_EVENTS.has(event)) {
mainWindow.webContents.send('account-rotation-log', entry); mainWindow.webContents.send('account-rotation-log', entry);
} }
}); });