This commit is contained in:
@@ -125,6 +125,8 @@ manager.on('disconnect', (conn) => {
|
||||
}
|
||||
if (!manager.active?.connected) {
|
||||
updateHealthBadge(null);
|
||||
lastStatsInterestSent = null;
|
||||
lastStatsInterestPeerId = null;
|
||||
}
|
||||
refreshFleetIfVisible();
|
||||
if (isBootRestoring) return;
|
||||
@@ -133,6 +135,8 @@ manager.on('disconnect', (conn) => {
|
||||
if (!hasActiveConnection()) {
|
||||
resetContainerList();
|
||||
stopStatsInterval();
|
||||
lastStatsInterestSent = null;
|
||||
lastStatsInterestPeerId = null;
|
||||
if (typeof manager.isReconnecting === 'function' && manager.isReconnecting()) {
|
||||
// reconnecting banner is driven by 'reconnecting' events
|
||||
return;
|
||||
@@ -160,6 +164,26 @@ manager.on('connect', (conn) => {
|
||||
{ latency: conn.latency, docker: conn.dockerHealth, status: conn.healthStatus },
|
||||
conn
|
||||
);
|
||||
// Re-declare view interest after (re)connect so stats streams resume if needed
|
||||
lastStatsInterestSent = null;
|
||||
lastStatsInterestPeerId = null;
|
||||
try {
|
||||
syncStatsInterest({ force: true });
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
});
|
||||
manager.on('active', (conn) => {
|
||||
// Switching fleet peer: re-send interest to the new active host
|
||||
lastStatsInterestSent = null;
|
||||
lastStatsInterestPeerId = null;
|
||||
if (conn?.connected) {
|
||||
try {
|
||||
syncStatsInterest({ force: true });
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
});
|
||||
/** Throttle reconnect notices (standard mode only) */
|
||||
@@ -419,6 +443,66 @@ function startStatsInterval() {
|
||||
stopStatsInterval();
|
||||
}
|
||||
|
||||
/**
|
||||
* Views that show live per-container CPU/memory (table or dashboard KPIs).
|
||||
* Server only opens Docker stats streams while ≥1 peer reports interest.
|
||||
*/
|
||||
const STATS_INTEREST_VIEWS = new Set(['containers', 'dashboard', 'container-details']);
|
||||
|
||||
/** @type {boolean|null} last interest sent for active peer (avoid spam) */
|
||||
let lastStatsInterestSent = null;
|
||||
/** @type {string|null} peer id we last told */
|
||||
let lastStatsInterestPeerId = null;
|
||||
|
||||
/**
|
||||
* Tell the active peer whether this UI needs live fleet stats.
|
||||
* Call on view change and after connect. Leaving Containers/Dashboard tears
|
||||
* down server-side Docker stats streams for this client.
|
||||
* @param {{ force?: boolean }} [opts]
|
||||
*/
|
||||
function syncStatsInterest(opts = {}) {
|
||||
const force = opts.force === true;
|
||||
const conn = manager.active;
|
||||
if (!conn?.connected) {
|
||||
lastStatsInterestSent = null;
|
||||
lastStatsInterestPeerId = null;
|
||||
return;
|
||||
}
|
||||
const view =
|
||||
typeof currentView === 'string'
|
||||
? currentView
|
||||
: typeof window !== 'undefined' && typeof window.currentView === 'string'
|
||||
? window.currentView
|
||||
: '';
|
||||
const want = STATS_INTEREST_VIEWS.has(view);
|
||||
if (
|
||||
!force &&
|
||||
lastStatsInterestSent === want &&
|
||||
lastStatsInterestPeerId === conn.id
|
||||
) {
|
||||
return;
|
||||
}
|
||||
lastStatsInterestSent = want;
|
||||
lastStatsInterestPeerId = conn.id;
|
||||
try {
|
||||
conn
|
||||
.request(Methods.setStatsInterest || 'setStatsInterest', {
|
||||
active: want,
|
||||
view: view || undefined,
|
||||
})
|
||||
.catch(() => {
|
||||
// older servers may lack the method — ignore
|
||||
lastStatsInterestSent = null;
|
||||
});
|
||||
} catch {
|
||||
lastStatsInterestSent = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
window.syncStatsInterest = syncStatsInterest;
|
||||
}
|
||||
|
||||
// Utility functions are now imported from uiUtils.js
|
||||
|
||||
|
||||
@@ -1384,6 +1468,13 @@ function navigateToView(viewName, opts = {}) {
|
||||
// Expose for auto-refresh poller
|
||||
if (typeof window !== 'undefined') window.currentView = viewName;
|
||||
|
||||
// Demand-driven fleet stats: only collect while on Containers / Dashboard / details
|
||||
try {
|
||||
syncStatsInterest();
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
|
||||
// Drop live streams / PTYs when leaving container details
|
||||
if (leavingDetails) {
|
||||
if (typeof stopDetailsLogs === 'function') stopDetailsLogs();
|
||||
|
||||
Reference in New Issue
Block a user