[grade=A] P2-5: fix 4 test handle leaks in log-digest.js + sweep remaining console calls

Root cause: setTimeout in start() (line 74) created an initial-collection
timer that was never stored in an instance property, so stop() could not
clear it. Tests called start() → afterEach stop(), but the orphaned handle
kept the test process alive (4 leaked handles across 4 test cases).

Fix: store as this._initialTimeout, clear in stop() alongside digestTimeout.

Also replaced 3 remaining console.error calls in log-digest.js with
structured log.error tagged 'logdigest' (was missed in P1-8 sweep).

1539/1539 tests pass. 0 open handles (--detectOpenHandles clean).
This commit is contained in:
Hermes
2026-08-10 21:16:22 -07:00
parent 4dda005eb1
commit 1bc41bb2bc
+9 -4
View File
@@ -11,6 +11,7 @@ const fs = require('fs');
const fsp = require('fs').promises; const fsp = require('fs').promises;
const path = require('path'); const path = require('path');
const { DOCKER } = require('../utilities/constants'); const { DOCKER } = require('../utilities/constants');
const { log } = require('../utils/logging');
const docker = new Docker(); const docker = new Docker();
@@ -63,7 +64,7 @@ class LogDigest extends EventEmitter {
// Collect logs every hour // Collect logs every hour
this.collectInterval = setInterval(() => { this.collectInterval = setInterval(() => {
this._collectHourlyLogs().catch(e => this._collectHourlyLogs().catch(e =>
console.error('[LogDigest] Hourly collection failed:', e.message) log.error('logdigest', e, { phase: 'hourlyCollect' })
); );
}, DOCKER.DIGEST.COLLECT_INTERVAL); }, DOCKER.DIGEST.COLLECT_INTERVAL);
@@ -71,7 +72,7 @@ class LogDigest extends EventEmitter {
this._scheduleDailyDigest(); this._scheduleDailyDigest();
// Run initial collection after 2 minutes // Run initial collection after 2 minutes
setTimeout(() => { this._initialTimeout = setTimeout(() => {
if (this.running) { if (this.running) {
this._collectHourlyLogs().catch(() => {}); this._collectHourlyLogs().catch(() => {});
} }
@@ -89,6 +90,10 @@ class LogDigest extends EventEmitter {
clearTimeout(this.digestTimeout); clearTimeout(this.digestTimeout);
this.digestTimeout = null; this.digestTimeout = null;
} }
if (this._initialTimeout) {
clearTimeout(this._initialTimeout);
this._initialTimeout = null;
}
} }
/** /**
@@ -195,7 +200,7 @@ class LogDigest extends EventEmitter {
hourSummary.services[appId] = serviceSummary; hourSummary.services[appId] = serviceSummary;
} }
} catch (e) { } catch (e) {
console.error('[LogDigest] Container enumeration failed:', e.message); log.error('logdigest', e, { phase: 'enumerateContainers' });
} }
// Add to ring buffer // Add to ring buffer
@@ -258,7 +263,7 @@ class LogDigest extends EventEmitter {
const delay = next.getTime() - now.getTime(); const delay = next.getTime() - now.getTime();
this.digestTimeout = setTimeout(() => { this.digestTimeout = setTimeout(() => {
this.generateDailyDigest().catch(e => this.generateDailyDigest().catch(e =>
console.error('[LogDigest] Daily digest generation failed:', e.message) log.error('logdigest', e, { phase: 'dailyDigest' })
); );
// Reschedule for tomorrow // Reschedule for tomorrow
if (this.running) this._scheduleDailyDigest(); if (this.running) this._scheduleDailyDigest();