Compare commits

..

1 Commits

Author SHA1 Message Date
CyberMind
0c01ab8297
Merge fcee198a9f into 4f8eb711f3 2026-06-25 12:53:54 +00:00

View File

@ -1711,31 +1711,26 @@
// If already ok/warn/error, keep that status until new result arrives // If already ok/warn/error, keep that status until new result arrives
}); });
// #740: ONE batch call instead of one /api/v1/<mod>/health per module. for (var i = 0; i < modules.length; i += BATCH_SIZE) {
// The per-module loop fired ~119 requests every cycle and hammered the var batch = modules.slice(i, i + BATCH_SIZE);
// aggregator's single shared event loop (board-wide 502s). The hub batch var results = await Promise.allSettled(batch.map(function(mod) {
// endpoint returns every module's status in a single hit. return checkModuleHealth(mod);
await applyHealthBatch(modules); }));
return healthCache;
results.forEach(function(result, idx) {
var mod = batch[idx];
if (result.status === 'fulfilled') {
healthCache[mod] = result.value;
} else {
healthCache[mod] = { status: 'error', msg: 'Check failed', timestamp: Date.now() };
}
});
// Update LEDs after each batch
updateAllLEDs();
} }
// Populate healthCache for `modules` from the single hub batch endpoint return healthCache;
// (/api/v1/hub/public/health-batch — served by the dedicated hub process,
// double-buffered). Replaces the per-module health storm.
async function applyHealthBatch(modules) {
var token = localStorage.getItem('sbx_token');
var headers = token ? { 'Authorization': 'Bearer ' + token } : {};
var res = await safeFetch(BATCH_HEALTH_API, { headers: headers }, 5000);
if (!res.ok || !res.data || !res.data.modules) return;
var mods = res.data.modules;
modules.forEach(function(mod) {
var hb = mods[mod] || mods[mod.replace(/_/g, '-')] || mods[mod.replace(/-/g, '_')];
healthCache[mod] = hb
? { status: hb.status, msg: hb.msg || '', timestamp: Date.now() }
: { status: 'unknown', msg: 'no health API', timestamp: Date.now() };
});
updateAllLEDs();
try { savePreCache(healthCache); } catch (e) {}
} }
async function refreshStaleHealth() { async function refreshStaleHealth() {
@ -1749,9 +1744,17 @@
if (stale.length === 0) return; if (stale.length === 0) return;
// #740: refresh stale modules via the single batch endpoint, not one // Incremental update - update each LED as result comes in
// /health request per module. for (var i = 0; i < stale.length; i += BATCH_SIZE) {
await applyHealthBatch(stale); var batch = stale.slice(i, i + BATCH_SIZE);
await Promise.allSettled(batch.map(async function(mod) {
var result = await checkModuleHealth(mod);
healthCache[mod] = result;
// Update single LED immediately
var item = document.querySelector('.nav-item[data-module="' + mod + '"]');
if (item) updateSingleLED(item, result);
}));
}
// Save cache once at end, no re-sort needed // Save cache once at end, no re-sort needed
savePreCache(healthCache); savePreCache(healthCache);