From 6792f5b7ea598322514373dbf5cc6dbc3cfe14c9 Mon Sep 17 00:00:00 2001 From: Dicken Date: Sat, 25 Jul 2026 13:17:44 +0200 Subject: [PATCH] round45: Sammel-Scan bearbeitet jetzt bis zu 10 Geraete gleichzeitig statt nacheinander (behebt sehr lange Gesamtdauer bei vielen Geraeten) --- apps/backend/src/routes/scan.ts | 62 +++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 23 deletions(-) diff --git a/apps/backend/src/routes/scan.ts b/apps/backend/src/routes/scan.ts index b6c4114..b6b393e 100644 --- a/apps/backend/src/routes/scan.ts +++ b/apps/backend/src/routes/scan.ts @@ -203,33 +203,49 @@ export async function scanRoutes(app: FastifyInstance): Promise { let cancelled = false; try { - for (const device of devices) { + // Mehrere Geräte GLEICHZEITIG scannen statt strikt nacheinander - + // bei z. B. 118 Geräten und je 10-30 Sekunden pro vollständigem + // Portscan hätte ein rein sequenzieller Durchlauf zusammen leicht + // 30+ Minuten gedauert. Batch-Größe bewusst moderat (nicht alle + // Geräte auf einmal): jeder einzelne Geräte-Scan öffnet intern schon + // bis zu 1000 gleichzeitige Verbindungen (siehe ports.ts) - zu viele + // Geräte gleichzeitig könnte das eigene Netz/den Docker-Host + // überlasten. + const CONCURRENT_DEVICES = 10; + for (let i = 0; i < devices.length; i += CONCURRENT_DEVICES) { if (isCancelRequested("devices")) { cancelled = true; break; } - updateJobProgress("devices", scannedCount, device.hostname); - if (!tryLockDevice(device.id)) { - // Für dieses eine Gerät läuft bereits ein separater Scan (z. B. - // über den "Jetzt scannen"-Button auf der Geräte-Seite) - - // überspringen statt zu überlappen, sonst könnten beide - // gleichzeitig denselben neuen Dienst anlegen wollen. - scannedCount++; - continue; - } - try { - const result = await performDeviceScan(device, true); - created += result.created; - updated += result.updated; - allStale.push(...result.staleServices); - allNameChanges.push(...result.nameChanges); - allNew.push(...result.newServices); - } catch { - // einzelnes fehlgeschlagenes Gerät soll den Rest nicht abbrechen - } finally { - unlockDevice(device.id); - } - scannedCount++; + const batch = devices.slice(i, i + CONCURRENT_DEVICES); + updateJobProgress("devices", scannedCount, batch.map((d) => d.hostname).join(", ")); + + await Promise.all( + batch.map(async (device) => { + if (!tryLockDevice(device.id)) { + // Für dieses eine Gerät läuft bereits ein separater Scan + // (z. B. über den "Jetzt scannen"-Button auf der + // Geräte-Seite) - überspringen statt zu überlappen, sonst + // könnten beide gleichzeitig denselben neuen Dienst anlegen + // wollen. + return; + } + try { + const result = await performDeviceScan(device, true); + created += result.created; + updated += result.updated; + allStale.push(...result.staleServices); + allNameChanges.push(...result.nameChanges); + allNew.push(...result.newServices); + } catch { + // einzelnes fehlgeschlagenes Gerät soll den Rest nicht abbrechen + } finally { + unlockDevice(device.id); + } + }) + ); + scannedCount += batch.length; + updateJobProgress("devices", scannedCount, null); } finishJob("devices", {