fix: prevent infinite loading screen by adding sweep timeouts
The dashboard would hang indefinitely on the loading screen because: 1. `bls.mjs` used a raw `fetch()` without any timeout/AbortSignal — if the BLS API was slow or unresponsive, it would block forever. 2. `runSource()` in `briefing.mjs` had no per-source timeout, so a single hanging API could stall the entire sweep indefinitely. 3. `server.mjs` loaded cached `latest.json` via a fire-and-forget promise (`.then()`) instead of `await`, meaning the dashboard never received the cached data before the sweep started. 4. `loading.html` relied solely on SSE for redirect — if the SSE connection missed the update event, the page would never redirect. Changes: - Add 15s AbortController timeout to BLS `getSeries()` fetch call - Add 30s per-source timeout via `Promise.race()` in `runSource()` - Await `synthesize()` when loading cached data so the dashboard serves instantly on restart when `runs/latest.json` exists - Add 5s fallback polling to loading page alongside SSE Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
19
server.mjs
19
server.mjs
@@ -408,7 +408,7 @@ async function start() {
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
server.on('listening', () => {
|
||||
server.on('listening', async () => {
|
||||
console.log(`[Crucix] Server running on http://localhost:${port}`);
|
||||
|
||||
// Auto-open browser
|
||||
@@ -420,17 +420,18 @@ async function start() {
|
||||
if (err) console.log('[Crucix] Could not auto-open browser:', err.message);
|
||||
});
|
||||
|
||||
// Try to load existing data first for instant display
|
||||
// Try to load existing data first for instant display (await so dashboard shows immediately)
|
||||
try {
|
||||
const existing = JSON.parse(readFileSync(join(RUNS_DIR, 'latest.json'), 'utf8'));
|
||||
synthesize(existing).then(data => {
|
||||
currentData = data;
|
||||
console.log('[Crucix] Loaded existing data from runs/latest.json');
|
||||
broadcast({ type: 'update', data: currentData });
|
||||
}).catch(() => {});
|
||||
} catch { /* no existing data */ }
|
||||
const data = await synthesize(existing);
|
||||
currentData = data;
|
||||
console.log('[Crucix] Loaded existing data from runs/latest.json — dashboard ready instantly');
|
||||
broadcast({ type: 'update', data: currentData });
|
||||
} catch {
|
||||
console.log('[Crucix] No existing data found — first sweep required');
|
||||
}
|
||||
|
||||
// Run first sweep
|
||||
// Run first sweep (refreshes data in background)
|
||||
console.log('[Crucix] Running initial sweep...');
|
||||
runSweepCycle().catch(err => {
|
||||
console.error('[Crucix] Initial sweep failed:', err.message || err);
|
||||
|
||||
Reference in New Issue
Block a user