From 82ce17a941255f2a6da59f7b907c28160812d749 Mon Sep 17 00:00:00 2001 From: Juergen Kunz Date: Sat, 21 Feb 2026 18:56:44 +0000 Subject: [PATCH] fix(monitoring,remoteingress,web): Prune old metrics buckets periodically, clear metrics caches on shutdown, simplify edge disconnect handling, and optimize network view data updates --- changelog.md | 9 +++++++ ts/00_commitinfo_data.ts | 2 +- ts/monitoring/classes.metricsmanager.ts | 9 +++++++ ts/remoteingress/classes.tunnel-manager.ts | 6 +---- ts_web/00_commitinfo_data.ts | 2 +- ts_web/elements/ops-view-network.ts | 31 +++++++++------------- 6 files changed, 34 insertions(+), 25 deletions(-) diff --git a/changelog.md b/changelog.md index 257e924..1a1de85 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,14 @@ # Changelog +## 2026-02-21 - 7.4.2 - fix(monitoring,remoteingress,web) +Prune old metrics buckets periodically, clear metrics caches on shutdown, simplify edge disconnect handling, and optimize network view data updates + +- Call pruneOldBuckets() each minute to proactively remove stale time-series buckets in MetricsManager +- Clear metricsCache, emailMinuteBuckets and dnsMinuteBuckets when MetricsManager stops to avoid stale state on shutdown +- On edgeDisconnected remove the edgeStatuses entry instead of mutating an existing record (more explicit cleanup) +- Remove unused traffic-timer variables and move requestsPerSec history updates from render() into updateNetworkData() to avoid unnecessary re-renders +- Optimize traffic data array updates by shifting in-place then reassigning arrays to preserve Lit reactivity and reduce intermediate allocations + ## 2026-02-21 - 7.4.1 - fix(dcrouter) replace console logging with structured logger, improve metrics logging, add terminal-ready wait in ops UI, bump dees-catalog patch diff --git a/ts/00_commitinfo_data.ts b/ts/00_commitinfo_data.ts index 4c44112..10ee0d4 100644 --- a/ts/00_commitinfo_data.ts +++ b/ts/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@serve.zone/dcrouter', - version: '7.4.1', + version: '7.4.2', description: 'A multifaceted routing service handling mail and SMS delivery functions.' } diff --git a/ts/monitoring/classes.metricsmanager.ts b/ts/monitoring/classes.metricsmanager.ts index 5b6ee0f..da39436 100644 --- a/ts/monitoring/classes.metricsmanager.ts +++ b/ts/monitoring/classes.metricsmanager.ts @@ -110,6 +110,9 @@ export class MetricsManager { this.securityMetrics.incidents = []; this.securityMetrics.lastResetDate = currentDate; } + + // Prune old time-series buckets every minute (don't wait for lazy query) + this.pruneOldBuckets(); }, 60000); // Check every minute logger.log('info', 'MetricsManager started'); @@ -123,6 +126,12 @@ export class MetricsManager { } this.smartMetrics.stop(); + + // Clear caches and time-series buckets on shutdown + this.metricsCache.clear(); + this.emailMinuteBuckets.clear(); + this.dnsMinuteBuckets.clear(); + logger.log('info', 'MetricsManager stopped'); } diff --git a/ts/remoteingress/classes.tunnel-manager.ts b/ts/remoteingress/classes.tunnel-manager.ts index 1e13ced..92c0dab 100644 --- a/ts/remoteingress/classes.tunnel-manager.ts +++ b/ts/remoteingress/classes.tunnel-manager.ts @@ -35,11 +35,7 @@ export class TunnelManager { }); this.hub.on('edgeDisconnected', (data: { edgeId: string }) => { - const existing = this.edgeStatuses.get(data.edgeId); - if (existing) { - existing.connected = false; - existing.activeTunnels = 0; - } + this.edgeStatuses.delete(data.edgeId); }); this.hub.on('streamOpened', (data: { edgeId: string; streamId: number }) => { diff --git a/ts_web/00_commitinfo_data.ts b/ts_web/00_commitinfo_data.ts index 4c44112..10ee0d4 100644 --- a/ts_web/00_commitinfo_data.ts +++ b/ts_web/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@serve.zone/dcrouter', - version: '7.4.1', + version: '7.4.2', description: 'A multifaceted routing service handling mail and SMS delivery functions.' } diff --git a/ts_web/elements/ops-view-network.ts b/ts_web/elements/ops-view-network.ts index 28884b6..18ffaca 100644 --- a/ts_web/elements/ops-view-network.ts +++ b/ts_web/elements/ops-view-network.ts @@ -47,9 +47,6 @@ export class OpsViewNetwork extends DeesElement { private lastChartUpdate = 0; private chartUpdateThreshold = 1000; // Minimum ms between chart updates - private lastTrafficUpdateTime = 0; - private trafficUpdateInterval = 1000; // Update every 1 second - private requestCountHistory = new Map(); // Track requests per time bucket private trafficUpdateTimer: any = null; private requestsPerSecHistory: number[] = []; // Track requests/sec over time for trend private historyLoaded = false; // Whether server-side throughput history has been loaded @@ -106,8 +103,6 @@ export class OpsViewNetwork extends DeesElement { this.trafficDataIn = [...emptyData]; this.trafficDataOut = emptyData.map(point => ({ ...point })); - - this.lastTrafficUpdateTime = now; } /** @@ -413,11 +408,7 @@ export class OpsViewNetwork extends DeesElement { const throughput = this.calculateThroughput(); const activeConnections = this.statsState.serverStats?.activeConnections || 0; - // Track requests/sec history for the trend sparkline - this.requestsPerSecHistory.push(reqPerSec); - if (this.requestsPerSecHistory.length > 20) { - this.requestsPerSecHistory.shift(); - } + // Build trend data from pre-computed history (mutated in updateNetworkData, not here) const trendData = [...this.requestsPerSecHistory]; while (trendData.length < 20) { trendData.unshift(0); @@ -529,6 +520,13 @@ export class OpsViewNetwork extends DeesElement { } private async updateNetworkData() { + // Track requests/sec history for the trend sparkline (moved out of render) + const reqPerSec = this.networkState.requestsPerSecond || 0; + this.requestsPerSecHistory.push(reqPerSec); + if (this.requestsPerSecHistory.length > 20) { + this.requestsPerSecHistory.shift(); + } + // Only update if connections changed significantly const newConnectionCount = this.networkState.connections.length; const oldConnectionCount = this.networkRequests.length; @@ -602,16 +600,13 @@ export class OpsViewNetwork extends DeesElement { y: Math.round(throughputOutMbps * 10) / 10 }; - // Efficient array updates - modify in place when possible + // In-place mutation then reassign for Lit reactivity (avoids 4 intermediate arrays) if (this.trafficDataIn.length >= 60) { - // Remove oldest and add newest - this.trafficDataIn = [...this.trafficDataIn.slice(1), newDataPointIn]; - this.trafficDataOut = [...this.trafficDataOut.slice(1), newDataPointOut]; - } else { - // Still filling up the initial data - this.trafficDataIn = [...this.trafficDataIn, newDataPointIn]; - this.trafficDataOut = [...this.trafficDataOut, newDataPointOut]; + this.trafficDataIn.shift(); + this.trafficDataOut.shift(); } + this.trafficDataIn = [...this.trafficDataIn, newDataPointIn]; + this.trafficDataOut = [...this.trafficDataOut, newDataPointOut]; this.lastChartUpdate = now; }