generated from Dicken/dickendock
round29: Scanner laufen jetzt als Hintergrund-Job im Backend (behebt API-Scan-504-Timeout und macht Scan-Status/-Fortschritt geraeteuebergreifend sichtbar)
This commit is contained in:
@@ -5,43 +5,51 @@ interface ScanActivity {
|
||||
pendingCount: number;
|
||||
}
|
||||
|
||||
function readJson<T>(key: string, fallback: T): T {
|
||||
try {
|
||||
const raw = sessionStorage.getItem(`launchpad:${key}`);
|
||||
return raw !== null ? (JSON.parse(raw) as T) : fallback;
|
||||
} catch {
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
function computeActivity(): ScanActivity {
|
||||
const running = readJson("scanner:bulkRunning", false);
|
||||
const staleServices = readJson<unknown[]>("scanner:bulkStaleServices", []);
|
||||
const nameChanges = readJson<unknown[]>("scanner:bulkNameChanges", []);
|
||||
const staleDevices = readJson<unknown[]>("scanner:staleDevices", []);
|
||||
const deviceChanges = readJson<unknown[]>("scanner:deviceChanges", []);
|
||||
const pendingCount =
|
||||
staleServices.length + nameChanges.length + staleDevices.length + deviceChanges.length;
|
||||
return { running, pendingCount };
|
||||
}
|
||||
|
||||
/**
|
||||
* Geräteübergreifender Hinweis, ob gerade ein Scan läuft oder es
|
||||
* unbestätigte Scan-Ergebnisse gibt (siehe Scanner-Seite, dort alles über
|
||||
* usePersistedState/sessionStorage gehalten) - für ein Abzeichen am
|
||||
* "Scanner"-Navigationspunkt, sichtbar von jeder Admin-Seite aus.
|
||||
*
|
||||
* sessionStorage-Änderungen aus einer ANDEREN Komponente im selben Tab
|
||||
* lösen kein "storage"-Event aus (das feuert nur tab-übergreifend) - daher
|
||||
* hier bewusst ein einfaches, günstiges Polling statt eines echten
|
||||
* Reaktivitäts-Mechanismus.
|
||||
* unbestätigte Scan-Ergebnisse gibt - für ein Abzeichen am
|
||||
* "Scanner"-Navigationspunkt, sichtbar von jeder Admin-Seite UND jedem
|
||||
* Gerät/Browser aus, da der Zustand jetzt vom BACKEND abgefragt wird
|
||||
* (siehe apps/backend/src/scanJobs.ts), nicht mehr aus dem lokalen
|
||||
* sessionStorage des jeweiligen Browsers gelesen wird - Ersteres kann
|
||||
* naturgemäß nicht geräteübergreifend sein.
|
||||
*/
|
||||
export function useScanActivity(): ScanActivity {
|
||||
const [activity, setActivity] = useState<ScanActivity>(() => computeActivity());
|
||||
const [activity, setActivity] = useState<ScanActivity>({ running: false, pendingCount: 0 });
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => setActivity(computeActivity()), 1500);
|
||||
return () => clearInterval(interval);
|
||||
let cancelled = false;
|
||||
|
||||
async function poll() {
|
||||
try {
|
||||
const [devicesRes, apisRes] = await Promise.all([
|
||||
fetch("/api/scan/devices/all/status"),
|
||||
fetch("/api/scan/apis/status"),
|
||||
]);
|
||||
if (cancelled) return;
|
||||
|
||||
const devicesStatus = devicesRes.ok ? await devicesRes.json() : null;
|
||||
const apisStatus = apisRes.ok ? await apisRes.json() : null;
|
||||
|
||||
const running = !!devicesStatus?.running || !!apisStatus?.running;
|
||||
|
||||
const lastResult = devicesStatus?.lastResult;
|
||||
const pendingCount = lastResult
|
||||
? (lastResult.nameChanges?.length ?? 0) + (lastResult.staleServices?.length ?? 0)
|
||||
: 0;
|
||||
|
||||
setActivity({ running, pendingCount });
|
||||
} catch {
|
||||
// Netzwerk-Hänger beim Poll ignorieren, nächster Versuch folgt.
|
||||
}
|
||||
}
|
||||
|
||||
poll();
|
||||
const interval = setInterval(poll, 2000);
|
||||
return () => {
|
||||
cancelled = true;
|
||||
clearInterval(interval);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return activity;
|
||||
|
||||
Reference in New Issue
Block a user