From 114d6d897ad7094ff5046fab66514d1f2ba83fc0 Mon Sep 17 00:00:00 2001 From: Kiran Niranjan Date: Thu, 12 Sep 2019 16:04:39 +0530 Subject: [PATCH] fix: SDA-1520 (Optimize memory refresh logic & make it randomize) (#782) * SDA-1520 - Optimize memory refresh logic & make it randomize * SDA-1520 - Change attributes, for MacOS use private else use residentSet --- src/app/memory-monitor.ts | 80 +++++++++++++++++++++++------------- src/renderer/preload-main.ts | 41 ++++++++++++++---- 2 files changed, 85 insertions(+), 36 deletions(-) diff --git a/src/app/memory-monitor.ts b/src/app/memory-monitor.ts index 068e2f30..7510cf18 100644 --- a/src/app/memory-monitor.ts +++ b/src/app/memory-monitor.ts @@ -1,5 +1,6 @@ import * as electron from 'electron'; +import { isMac } from '../common/env'; import { logger } from '../common/logger'; import { config } from './config-handler'; import { windowHandler } from './window-handler'; @@ -9,6 +10,7 @@ class MemoryMonitor { private memoryInfo: Electron.ProcessMemoryInfo | undefined = undefined; private isInMeeting: boolean; private canReload: boolean; + private lastReloadTime?: number; private readonly maxIdleTime: number; private readonly memoryThreshold: number; @@ -17,9 +19,9 @@ class MemoryMonitor { constructor() { this.isInMeeting = false; this.canReload = true; - this.maxIdleTime = 4 * 60 * 60 * 1000; // 4 hours + this.maxIdleTime = 4 * 60 * 60 * 1000; // user activity threshold 4 hours this.memoryThreshold = 800 * 1024; // 800MB - this.memoryRefreshThreshold = 60 * 60 * 1000; // 1 hour + this.memoryRefreshThreshold = 24 * 60 * 60 * 1000; // 24 hour } /** @@ -51,40 +53,62 @@ class MemoryMonitor { logger.info(`memory-monitor: validating memory refresh conditions`); const { memoryRefresh } = config.getConfigFields([ 'memoryRefresh' ]); if (!memoryRefresh) { - logger.info(`memory-monitor: memory refresh is disabled in the config, not going to refresh!`); + logger.info(`memory-monitor: memory reload is disabled in the config, not going to refresh!`); return; } (electron.powerMonitor as any).querySystemIdleTime((time) => { const idleTime = time * 1000; - if (!(!this.isInMeeting - && windowHandler.isOnline - && this.canReload - && idleTime > this.maxIdleTime - && (this.memoryInfo && this.memoryInfo.private > this.memoryThreshold)) - ) { - logger.info(`memory-monitor: Not Reloading the app as - application was refreshed less than a hour ago? ${this.canReload ? 'no' : 'yes'} - memory consumption is ${(this.memoryInfo && this.memoryInfo.private) || 'unknown'}kb is less than? ${this.memoryThreshold}kb - system idle tick was ${idleTime}ms is less than? ${this.maxIdleTime}ms - user was in a meeting? ${this.isInMeeting} - is network online? ${windowHandler.isOnline}`); + // for MacOS use private else use residentSet + const memoryConsumption = isMac ? (this.memoryInfo && this.memoryInfo.private) : (this.memoryInfo && this.memoryInfo.residentSet); + logger.info(`memory-monitor: Checking different conditions to see if we should auto reload the app`); + + logger.info(`memory-monitor: Is in meeting: `, this.isInMeeting); + logger.info(`memory-monitor: Is Network online: `, windowHandler.isOnline); + logger.info(`memory-monitor: Memory consumption: `, memoryConsumption); + logger.info(`memory-monitor: Idle Time: `, idleTime); + logger.info(`memory-monitor: Last Reload time: `, this.lastReloadTime); + + if (this.isInMeeting) { + logger.info(`memory-monitor: NOT RELOADING -> User is currently in a meeting. Meeting status from client: `, this.isInMeeting); return; } - const mainWindow = windowHandler.getMainWindow(); - if (mainWindow && windowExists(mainWindow)) { - logger.info(`memory-monitor: Reloading the app to optimize memory usage as - memory consumption is ${this.memoryInfo.private}kb is greater than? ${this.memoryThreshold}kb threshold - system idle tick was ${idleTime}ms is greater than ${this.maxIdleTime}ms - user was in a meeting? ${this.isInMeeting} - is network online? ${windowHandler.isOnline}`); - windowHandler.setIsAutoReload(true); - mainWindow.reload(); - this.canReload = false; - setTimeout(() => { - this.canReload = true; - }, this.memoryRefreshThreshold); + + if (!windowHandler.isOnline) { + logger.info(`memory-monitor: NOT RELOADING -> Not connected to network. Network status: `, windowHandler.isOnline); + return; } + + if (!(memoryConsumption && memoryConsumption > this.memoryThreshold)) { + logger.info(`memory-monitor: NOT RELOADING -> Memory consumption ${memoryConsumption} is lesser than the threshold ${this.memoryThreshold}`); + return; + } + + if (!(idleTime > this.maxIdleTime)) { + logger.info(`memory-monitor: NOT RELOADING -> User is not idle for: `, idleTime); + return; + } + + if (!this.canReload) { + logger.info(`memory-monitor: NOT RELOADING -> Already refreshed at: `, this.lastReloadTime); + return; + } + + const mainWindow = windowHandler.getMainWindow(); + if (!(mainWindow && windowExists(mainWindow))) { + logger.info(`memory-monitor: NOT RELOADING -> Main window doesn't exist!`); + return; + } + + logger.info(`memory-monitor: RELOADING -> auto reloading the app as all the conditions are satisfied`); + + windowHandler.setIsAutoReload(true); + mainWindow.reload(); + this.canReload = false; + this.lastReloadTime = new Date().getTime(); + setTimeout(() => { + this.canReload = true; + }, this.memoryRefreshThreshold); // prevents multiple reloading of the client within 24hrs }); } } diff --git a/src/renderer/preload-main.ts b/src/renderer/preload-main.ts index 3a4a68b2..d9462361 100644 --- a/src/renderer/preload-main.ts +++ b/src/renderer/preload-main.ts @@ -16,7 +16,8 @@ interface ISSFWindow extends Window { } const ssfWindow: ISSFWindow = window; -const memoryInfoFetchInterval = 60 * 60 * 1000; +const minMemoryFetchInterval = 4 * 60 * 60 * 1000; +const maxMemoryFetchInterval = 12 * 60 * 60 * 1000; const snackBar = new SnackBar(); /** @@ -43,6 +44,36 @@ const createAPI = () => { createAPI(); +/** + * Returns a random number that is between (min - max) + * if min is 4hrs and max is 12hrs then the + * returned value will be a random b/w 4 - 12 hrs + * + * @param min {number} - millisecond + * @param max {number} - millisecond + */ +const getRandomTime = (min, max) => { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min + 1)) + min; +}; + +/** + * Monitory memory with a randomized time + * + * @param time + */ +const monitorMemory = (time) => { + setTimeout(async () => { + const memoryInfo = await process.getProcessMemoryInfo(); + ipcRenderer.send(apiName.symphonyApi, { + cmd: apiCmds.memoryInfo, + memoryInfo, + }); + monitorMemory(getRandomTime(minMemoryFetchInterval, maxMemoryFetchInterval)); + }, time); +}; + // When the window is completely loaded ipcRenderer.on('page-load', (_event, { locale, resources, enableCustomTitleBar, isMainWindow }) => { @@ -76,13 +107,7 @@ ipcRenderer.on('page-load', (_event, { locale, resources, enableCustomTitleBar, downloadManager.initDownloadManager(); if (isMainWindow) { - setInterval(async () => { - const memoryInfo = await process.getProcessMemoryInfo(); - ipcRenderer.send(apiName.symphonyApi, { - cmd: apiCmds.memoryInfo, - memoryInfo, - }); - }, memoryInfoFetchInterval); + monitorMemory(getRandomTime(minMemoryFetchInterval, maxMemoryFetchInterval)); } });