From c3f363046e44c08cfc871a3230f354128e6a8c9c Mon Sep 17 00:00:00 2001 From: MariiaNebesnova Date: Mon, 24 Jul 2023 18:17:46 +0300 Subject: [PATCH 1/6] fix deboncer memory leaks --- src/app/store/store.ts | 3 +- src/common/utils/debouncer.ts | 40 ++++++++++++++----- .../selectors/locatorsFiltered.selectors.ts | 8 ++++ 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/app/store/store.ts b/src/app/store/store.ts index 67321791..e8abb819 100644 --- a/src/app/store/store.ts +++ b/src/app/store/store.ts @@ -11,6 +11,7 @@ import { scriptNotifier } from "../../pageServices/scriptNotifier"; import { changePageMiddleware } from "./middlewares/changePage.middleware"; import { updateSocketMessageHandler } from "../../services/webSocketMessageHandler"; import { onSetActive } from "../../features/locators/reducers/onSetActive.middleware"; +import { quitDebouncerMiddleware } from "../../common/utils/debouncer"; const rootReducer = { main: mainSlice, @@ -33,7 +34,7 @@ export const store = configureStore({ "main/setScriptMessage", ], }, - }).concat([logger, scriptNotifier, cancellableActions, changePageMiddleware, onSetActive]), + }).concat([logger, scriptNotifier, cancellableActions, changePageMiddleware, onSetActive, quitDebouncerMiddleware]), }); store.subscribe(() => updateMessageHandler(store.dispatch, store.getState())); diff --git a/src/common/utils/debouncer.ts b/src/common/utils/debouncer.ts index 3c3c4149..2f6e6500 100644 --- a/src/common/utils/debouncer.ts +++ b/src/common/utils/debouncer.ts @@ -1,7 +1,9 @@ +import { Middleware } from "@reduxjs/toolkit"; +import { areInProgress } from "../../features/locators/selectors/locatorsFiltered.selectors"; + class Debouncer { accumulatedArgs: any[] = []; interval: NodeJS.Timer | null = null; - cancelTimeout: NodeJS.Timeout | null = null; constructor() { this.accumulateAndDebounce = this.accumulateAndDebounce.bind(this); @@ -13,17 +15,15 @@ class Debouncer { }; const throttledFn = () => { - if (this.accumulatedArgs.length > 0) { - this.cancelTimeout && clearTimeout(this.cancelTimeout); + if (this.accumulatedArgs.length === 0) return; + + try { fn(this.accumulatedArgs); - this.accumulatedArgs = []; - } else { - if (this.cancelTimeout) return; - this.cancelTimeout = setTimeout(() => { - this.interval && clearInterval(this.interval); - this.interval = null; - }, 30000); + } catch (error) { + this.quitDebouncer(); + if (__DEV_ENVIRONMENT__) console.log("Can't invoke throttled function:", error); } + this.accumulatedArgs = []; }; if (!this.interval) this.interval = setInterval(throttledFn, 500); @@ -32,6 +32,26 @@ class Debouncer { debouncedFn(args); }; } + + quitDebouncer() { + this.interval && clearInterval(this.interval); + this.interval = null; + } } export const debouncer = new Debouncer(); + +export const quitDebouncerMiddleware: Middleware = (store) => (next) => (action) => { + const result = next(action); + + switch (action.type) { + case "locators/updateLocatorGroup": + case "locators/failGeneration": + if (!areInProgress(store.getState())) { + debouncer.quitDebouncer(); + } + break; + } + + return result; +}; diff --git a/src/features/locators/selectors/locatorsFiltered.selectors.ts b/src/features/locators/selectors/locatorsFiltered.selectors.ts index 1c12eef7..dbbad593 100644 --- a/src/features/locators/selectors/locatorsFiltered.selectors.ts +++ b/src/features/locators/selectors/locatorsFiltered.selectors.ts @@ -6,6 +6,8 @@ import { Locator } from "../types/locator.types"; import { filterLocatorsByClassFilter } from "../utils/filterLocators"; import { isProgressStatus } from "../utils/locatorGenerationController"; import { selectLocatorsByPageObject, selectSortedLocators } from "./locatorsByPO.selectors"; +import { selectCurrentPage } from "../../../app/main.selectors"; +import { isLocatorListPage } from "../../../app/utils/heplers"; export const selectFilteredLocators = createSelector( selectLocatorsByPageObject, @@ -148,3 +150,9 @@ export const selectActiveLocators = createSelector(selectFilteredLocators, (loca export const selectCheckedLocators = createSelector(selectFilteredLocators, (locators) => locators.filter((_loc) => _loc.generate) ); + +export const areInProgress = createSelector( + selectInProgressByPageObj, + selectCurrentPage, + (locators, page) => isLocatorListPage(page.page) && locators.length > 0 +); From a012ff6ed02eea98e533eecd7653fd3d42dcf778 Mon Sep 17 00:00:00 2001 From: MariiaNebesnova Date: Mon, 24 Jul 2023 18:29:42 +0300 Subject: [PATCH 2/6] prevent redundant reducer invokations --- src/services/webSocketMessageHandler.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/services/webSocketMessageHandler.ts b/src/services/webSocketMessageHandler.ts index b8dc31e5..ff8a122a 100644 --- a/src/services/webSocketMessageHandler.ts +++ b/src/services/webSocketMessageHandler.ts @@ -6,7 +6,7 @@ import { NETWORK_ERROR, NO_ELEMENT_IN_DOCUMENT } from "../features/locators/util import { locatorGenerationController } from "../features/locators/utils/locatorGenerationController"; import { sendMessage } from "../pageServices/connector"; import { webSocketController } from "./webSocketController"; -import { selectInProgressByPageObj } from "../features/locators/selectors/locatorsFiltered.selectors"; +import { areInProgress, selectInProgressByPageObj } from "../features/locators/selectors/locatorsFiltered.selectors"; import { selectCurrentPageObject } from "../features/pageObjects/selectors/pageObjects.selectors"; const reScheduledTasks = new Set(); @@ -63,13 +63,12 @@ export const updateSocketMessageHandler = (dispatch: any, state: any) => { const pageObject = selectCurrentPageObject(state)!; dispatch(updateLocatorGroup({ locators, pageObject })); }; - debouncer.accumulateAndDebounce(onStatusChange)([payload]); + if (areInProgress(state)) debouncer.accumulateAndDebounce(onStatusChange)([payload]); break; } } if (pong) { - const areInProgress = selectInProgressByPageObj(state).length > 0; - if (!areInProgress) webSocketController.stopPing(); + if (!areInProgress(state)) webSocketController.stopPing(); } }; From 5f69627533d0e0267a4c2a35160944753df13509 Mon Sep 17 00:00:00 2001 From: MariiaNebesnova Date: Tue, 25 Jul 2023 10:12:24 +0300 Subject: [PATCH 3/6] fix memory leaks --- src/app/store/store.ts | 2 +- src/common/utils/{debouncer.ts => throttler.ts} | 14 +++++++------- src/services/webSocketMessageHandler.ts | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) rename src/common/utils/{debouncer.ts => throttler.ts} (81%) diff --git a/src/app/store/store.ts b/src/app/store/store.ts index e8abb819..9e1bebd2 100644 --- a/src/app/store/store.ts +++ b/src/app/store/store.ts @@ -11,7 +11,7 @@ import { scriptNotifier } from "../../pageServices/scriptNotifier"; import { changePageMiddleware } from "./middlewares/changePage.middleware"; import { updateSocketMessageHandler } from "../../services/webSocketMessageHandler"; import { onSetActive } from "../../features/locators/reducers/onSetActive.middleware"; -import { quitDebouncerMiddleware } from "../../common/utils/debouncer"; +import { quitDebouncerMiddleware } from "../../common/utils/throttler"; const rootReducer = { main: mainSlice, diff --git a/src/common/utils/debouncer.ts b/src/common/utils/throttler.ts similarity index 81% rename from src/common/utils/debouncer.ts rename to src/common/utils/throttler.ts index 2f6e6500..e53839d6 100644 --- a/src/common/utils/debouncer.ts +++ b/src/common/utils/throttler.ts @@ -1,15 +1,15 @@ import { Middleware } from "@reduxjs/toolkit"; import { areInProgress } from "../../features/locators/selectors/locatorsFiltered.selectors"; -class Debouncer { +class Throttler { accumulatedArgs: any[] = []; interval: NodeJS.Timer | null = null; constructor() { - this.accumulateAndDebounce = this.accumulateAndDebounce.bind(this); + this.accumulateAndThrottle = this.accumulateAndThrottle.bind(this); } - accumulateAndDebounce(fn: (arg: any[]) => any) { + accumulateAndThrottle(fn: (arg: any[]) => any) { const debouncedFn = (args: any[]) => { this.accumulatedArgs.push(...args); }; @@ -20,7 +20,7 @@ class Debouncer { try { fn(this.accumulatedArgs); } catch (error) { - this.quitDebouncer(); + this.quitThrottler(); if (__DEV_ENVIRONMENT__) console.log("Can't invoke throttled function:", error); } this.accumulatedArgs = []; @@ -33,13 +33,13 @@ class Debouncer { }; } - quitDebouncer() { + quitThrottler() { this.interval && clearInterval(this.interval); this.interval = null; } } -export const debouncer = new Debouncer(); +export const throttler = new Throttler(); export const quitDebouncerMiddleware: Middleware = (store) => (next) => (action) => { const result = next(action); @@ -48,7 +48,7 @@ export const quitDebouncerMiddleware: Middleware = (store) => (next) => (action) case "locators/updateLocatorGroup": case "locators/failGeneration": if (!areInProgress(store.getState())) { - debouncer.quitDebouncer(); + throttler.quitThrottler(); } break; } diff --git a/src/services/webSocketMessageHandler.ts b/src/services/webSocketMessageHandler.ts index ff8a122a..d8310c1a 100644 --- a/src/services/webSocketMessageHandler.ts +++ b/src/services/webSocketMessageHandler.ts @@ -1,4 +1,4 @@ -import { debouncer } from "../common/utils/debouncer"; +import { throttler } from "../common/utils/throttler"; import { failGeneration, updateLocatorGroup } from "../features/locators/locators.slice"; import { selectLocatorByJdnHash } from "../features/locators/selectors/locators.selectors"; import { Locator, LocatorTaskStatus } from "../features/locators/types/locator.types"; @@ -63,7 +63,7 @@ export const updateSocketMessageHandler = (dispatch: any, state: any) => { const pageObject = selectCurrentPageObject(state)!; dispatch(updateLocatorGroup({ locators, pageObject })); }; - if (areInProgress(state)) debouncer.accumulateAndDebounce(onStatusChange)([payload]); + if (areInProgress(state)) throttler.accumulateAndThrottle(onStatusChange)([payload]); break; } } From c4f0ffb3ae446de32dd1e64242c8ded44e40d4ea Mon Sep 17 00:00:00 2001 From: MariiaNebesnova Date: Tue, 25 Jul 2023 10:13:28 +0300 Subject: [PATCH 4/6] ver up --- manifest.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/manifest.json b/manifest.json index 45033838..2b23d89d 100644 --- a/manifest.json +++ b/manifest.json @@ -3,7 +3,7 @@ "name": "JDN", "description": "JDN – helps Test Automation Engineer to create Page Objects in the test automation framework and speed up test development", "devtools_page": "index.html", - "version": "3.13.532", + "version": "3.13.533", "icons": { "128": "icon128.png" }, diff --git a/package.json b/package.json index 08c01967..b3f08c28 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "jdn-ai-chrome-extension", - "version": "3.13.532", + "version": "3.13.533", "description": "jdn-ai chrome extension", "scripts": { "start": "webpack --watch --env devenv", From 1477dd447b9d333225e9441c144295e73c931ad6 Mon Sep 17 00:00:00 2001 From: MariiaNebesnova Date: Tue, 25 Jul 2023 11:43:16 +0300 Subject: [PATCH 5/6] rename --- src/app/store/store.ts | 4 ++-- src/common/utils/throttler.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/store/store.ts b/src/app/store/store.ts index 9e1bebd2..f42d9bb2 100644 --- a/src/app/store/store.ts +++ b/src/app/store/store.ts @@ -11,7 +11,7 @@ import { scriptNotifier } from "../../pageServices/scriptNotifier"; import { changePageMiddleware } from "./middlewares/changePage.middleware"; import { updateSocketMessageHandler } from "../../services/webSocketMessageHandler"; import { onSetActive } from "../../features/locators/reducers/onSetActive.middleware"; -import { quitDebouncerMiddleware } from "../../common/utils/throttler"; +import { quitThrottlerMiddleware } from "../../common/utils/throttler"; const rootReducer = { main: mainSlice, @@ -34,7 +34,7 @@ export const store = configureStore({ "main/setScriptMessage", ], }, - }).concat([logger, scriptNotifier, cancellableActions, changePageMiddleware, onSetActive, quitDebouncerMiddleware]), + }).concat([logger, scriptNotifier, cancellableActions, changePageMiddleware, onSetActive, quitThrottlerMiddleware]), }); store.subscribe(() => updateMessageHandler(store.dispatch, store.getState())); diff --git a/src/common/utils/throttler.ts b/src/common/utils/throttler.ts index e53839d6..c857986e 100644 --- a/src/common/utils/throttler.ts +++ b/src/common/utils/throttler.ts @@ -41,7 +41,7 @@ class Throttler { export const throttler = new Throttler(); -export const quitDebouncerMiddleware: Middleware = (store) => (next) => (action) => { +export const quitThrottlerMiddleware: Middleware = (store) => (next) => (action) => { const result = next(action); switch (action.type) { From 4e50440776ef3efa05fd9b110d98c2bd25e09bf2 Mon Sep 17 00:00:00 2001 From: MariiaNebesnova Date: Tue, 25 Jul 2023 12:57:52 +0300 Subject: [PATCH 6/6] ver up --- manifest.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/manifest.json b/manifest.json index 2b23d89d..c54f3d45 100644 --- a/manifest.json +++ b/manifest.json @@ -3,7 +3,7 @@ "name": "JDN", "description": "JDN – helps Test Automation Engineer to create Page Objects in the test automation framework and speed up test development", "devtools_page": "index.html", - "version": "3.13.533", + "version": "3.13.534", "icons": { "128": "icon128.png" }, diff --git a/package.json b/package.json index b3f08c28..a44ec641 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "jdn-ai-chrome-extension", - "version": "3.13.533", + "version": "3.13.534", "description": "jdn-ai chrome extension", "scripts": { "start": "webpack --watch --env devenv",