fix(ops-view-network): centralize traffic chart timing constants for consistent rolling window updates

This commit is contained in:
2026-04-03 08:18:28 +00:00
parent 9c0e46ff4e
commit b46247d9cb
4 changed files with 31 additions and 20 deletions

View File

@@ -1,5 +1,12 @@
# Changelog # Changelog
## 2026-04-03 - 12.5.1 - fix(ops-view-network)
centralize traffic chart timing constants for consistent rolling window updates
- Defines shared constants for the chart window, update interval, and maximum buffered data points
- Replaces hardcoded traffic history sizes and timer intervals with derived values across initialization, history loading, and live updates
- Keeps the chart rolling window configuration aligned with the in-memory traffic buffer
## 2026-04-02 - 12.5.0 - feat(ops-view-routes) ## 2026-04-02 - 12.5.0 - feat(ops-view-routes)
add priority support and list-based domain editing for routes add priority support and list-based domain editing for routes

View File

@@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@serve.zone/dcrouter', name: '@serve.zone/dcrouter',
version: '12.5.0', version: '12.5.1',
description: 'A multifaceted routing service handling mail and SMS delivery functions.' description: 'A multifaceted routing service handling mail and SMS delivery functions.'
} }

View File

@@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@serve.zone/dcrouter', name: '@serve.zone/dcrouter',
version: '12.5.0', version: '12.5.1',
description: 'A multifaceted routing service handling mail and SMS delivery functions.' description: 'A multifaceted routing service handling mail and SMS delivery functions.'
} }

View File

@@ -28,6 +28,13 @@ interface INetworkRequest {
@customElement('ops-view-network') @customElement('ops-view-network')
export class OpsViewNetwork extends DeesElement { export class OpsViewNetwork extends DeesElement {
/** How far back the traffic chart shows */
private static readonly CHART_WINDOW_MS = 5 * 60 * 1000; // 5 minutes
/** How often a new data point is added */
private static readonly UPDATE_INTERVAL_MS = 1000; // 1 second
/** Derived: max data points the buffer holds */
private static readonly MAX_DATA_POINTS = OpsViewNetwork.CHART_WINDOW_MS / OpsViewNetwork.UPDATE_INTERVAL_MS;
@state() @state()
accessor statsState = appstate.statsStatePart.getState()!; accessor statsState = appstate.statsStatePart.getState()!;
@@ -46,7 +53,7 @@ export class OpsViewNetwork extends DeesElement {
// Track if we need to update the chart to avoid unnecessary re-renders // Track if we need to update the chart to avoid unnecessary re-renders
private lastChartUpdate = 0; private lastChartUpdate = 0;
private chartUpdateThreshold = 1000; // Minimum ms between chart updates private chartUpdateThreshold = OpsViewNetwork.UPDATE_INTERVAL_MS; // Minimum ms between chart updates
private trafficUpdateTimer: any = null; private trafficUpdateTimer: any = null;
private requestsPerSecHistory: number[] = []; // Track requests/sec over time for trend private requestsPerSecHistory: number[] = []; // Track requests/sec over time for trend
@@ -104,13 +111,11 @@ export class OpsViewNetwork extends DeesElement {
private initializeTrafficData() { private initializeTrafficData() {
const now = Date.now(); const now = Date.now();
// Fixed 5 minute time range const { MAX_DATA_POINTS, UPDATE_INTERVAL_MS } = OpsViewNetwork;
const range = 5 * 60 * 1000; // 5 minutes
const bucketSize = range / 60; // 60 data points
// Initialize with empty data points for both in and out // Initialize with empty data points for both in and out
const emptyData = Array.from({ length: 60 }, (_, i) => { const emptyData = Array.from({ length: MAX_DATA_POINTS }, (_, i) => {
const time = now - ((59 - i) * bucketSize); const time = now - ((MAX_DATA_POINTS - 1 - i) * UPDATE_INTERVAL_MS);
return { return {
x: new Date(time).toISOString(), x: new Date(time).toISOString(),
y: 0, y: 0,
@@ -143,23 +148,23 @@ export class OpsViewNetwork extends DeesElement {
y: Math.round((p.out * 8) / 1000000 * 10) / 10, y: Math.round((p.out * 8) / 1000000 * 10) / 10,
})); }));
// Use history as the chart data, keeping the most recent 60 points (5 min window) const { MAX_DATA_POINTS, UPDATE_INTERVAL_MS } = OpsViewNetwork;
const sliceStart = Math.max(0, historyIn.length - 60);
// Use history as the chart data, keeping the most recent points within the window
const sliceStart = Math.max(0, historyIn.length - MAX_DATA_POINTS);
this.trafficDataIn = historyIn.slice(sliceStart); this.trafficDataIn = historyIn.slice(sliceStart);
this.trafficDataOut = historyOut.slice(sliceStart); this.trafficDataOut = historyOut.slice(sliceStart);
// If fewer than 60 points, pad the front with zeros // If fewer than MAX_DATA_POINTS, pad the front with zeros
if (this.trafficDataIn.length < 60) { if (this.trafficDataIn.length < MAX_DATA_POINTS) {
const now = Date.now(); const now = Date.now();
const range = 5 * 60 * 1000; const padCount = MAX_DATA_POINTS - this.trafficDataIn.length;
const bucketSize = range / 60;
const padCount = 60 - this.trafficDataIn.length;
const firstTimestamp = this.trafficDataIn.length > 0 const firstTimestamp = this.trafficDataIn.length > 0
? new Date(this.trafficDataIn[0].x).getTime() ? new Date(this.trafficDataIn[0].x).getTime()
: now; : now;
const padIn = Array.from({ length: padCount }, (_, i) => ({ const padIn = Array.from({ length: padCount }, (_, i) => ({
x: new Date(firstTimestamp - ((padCount - i) * bucketSize)).toISOString(), x: new Date(firstTimestamp - ((padCount - i) * UPDATE_INTERVAL_MS)).toISOString(),
y: 0, y: 0,
})); }));
const padOut = padIn.map(p => ({ ...p })); const padOut = padIn.map(p => ({ ...p }));
@@ -296,7 +301,7 @@ export class OpsViewNetwork extends DeesElement {
} }
]} ]}
.realtimeMode=${true} .realtimeMode=${true}
.rollingWindow=${300000} .rollingWindow=${OpsViewNetwork.CHART_WINDOW_MS}
.yAxisFormatter=${(val: number) => `${val} Mbit/s`} .yAxisFormatter=${(val: number) => `${val} Mbit/s`}
></dees-chart-area> ></dees-chart-area>
@@ -709,9 +714,8 @@ export class OpsViewNetwork extends DeesElement {
private startTrafficUpdateTimer() { private startTrafficUpdateTimer() {
this.stopTrafficUpdateTimer(); // Clear any existing timer this.stopTrafficUpdateTimer(); // Clear any existing timer
this.trafficUpdateTimer = setInterval(() => { this.trafficUpdateTimer = setInterval(() => {
// Add a new data point every second
this.addTrafficDataPoint(); this.addTrafficDataPoint();
}, 1000); // Update every second }, OpsViewNetwork.UPDATE_INTERVAL_MS);
} }
private addTrafficDataPoint() { private addTrafficDataPoint() {
@@ -742,7 +746,7 @@ export class OpsViewNetwork extends DeesElement {
}; };
// In-place mutation then reassign for Lit reactivity (avoids 4 intermediate arrays) // In-place mutation then reassign for Lit reactivity (avoids 4 intermediate arrays)
if (this.trafficDataIn.length >= 60) { if (this.trafficDataIn.length >= OpsViewNetwork.MAX_DATA_POINTS) {
this.trafficDataIn.shift(); this.trafficDataIn.shift();
this.trafficDataOut.shift(); this.trafficDataOut.shift();
} }