From cad4547b29723c59b51f2eaade963a16d4d541dd Mon Sep 17 00:00:00 2001 From: Jaanus Sellin Date: Tue, 12 Sep 2023 11:43:01 +0300 Subject: [PATCH] fix: last seen environment remove duplicate entries (#4663) --- .../client-metrics/last-seen-service.test.ts | 61 +++++++++++++++++++ .../client-metrics/last-seen-service.ts | 21 ++++--- 2 files changed, 75 insertions(+), 7 deletions(-) create mode 100644 src/lib/services/client-metrics/last-seen-service.test.ts diff --git a/src/lib/services/client-metrics/last-seen-service.test.ts b/src/lib/services/client-metrics/last-seen-service.test.ts new file mode 100644 index 000000000000..90f181772a7b --- /dev/null +++ b/src/lib/services/client-metrics/last-seen-service.test.ts @@ -0,0 +1,61 @@ +import createStores from '../../../test/fixtures/store'; +import EventEmitter from 'events'; +import getLogger from '../../../test/fixtures/no-logger'; +import { IUnleashConfig } from '../../types'; +import { LastSeenService } from './last-seen-service'; + +function initLastSeenService(flagEnabled = true) { + const stores = createStores(); + + const eventBus = new EventEmitter(); + eventBus.emit = jest.fn(); + + const config = { + eventBus, + getLogger, + flagResolver: { + isEnabled: () => { + return flagEnabled; + }, + }, + } as unknown as IUnleashConfig; + + const lastSeenService = new LastSeenService(stores, config); + + return { lastSeenService, featureToggleStore: stores.featureToggleStore }; +} + +test('should not add duplicates per feature/environment', async () => { + const { lastSeenService, featureToggleStore } = initLastSeenService(); + + lastSeenService.updateLastSeen([ + { + featureName: 'myFeature', + environment: 'development', + yes: 1, + no: 0, + appName: 'test', + timestamp: new Date(), + }, + ]); + + lastSeenService.updateLastSeen([ + { + featureName: 'myFeature', + environment: 'development', + yes: 1, + no: 0, + appName: 'test', + timestamp: new Date(), + }, + ]); + featureToggleStore.setLastSeen = jest.fn(); + await lastSeenService.store(); + + expect(featureToggleStore.setLastSeen).toHaveBeenCalledWith([ + { + environment: 'development', + featureName: 'myFeature', + }, + ]); +}); diff --git a/src/lib/services/client-metrics/last-seen-service.ts b/src/lib/services/client-metrics/last-seen-service.ts index 640a87f57aab..c4d9564f4993 100644 --- a/src/lib/services/client-metrics/last-seen-service.ts +++ b/src/lib/services/client-metrics/last-seen-service.ts @@ -13,7 +13,7 @@ export type LastSeenInput = { export class LastSeenService { private timers: NodeJS.Timeout[] = []; - private lastSeenToggles: Set = new Set(); + private lastSeenToggles: Map = new Map(); private logger: Logger; @@ -37,8 +37,8 @@ export class LastSeenService { async store(): Promise { const count = this.lastSeenToggles.size; if (count > 0) { - const lastSeenToggles = [...this.lastSeenToggles]; - this.lastSeenToggles = new Set(); + const lastSeenToggles = Array.from(this.lastSeenToggles.values()); + this.lastSeenToggles = new Map(); this.logger.debug( `Updating last seen for ${lastSeenToggles.length} toggles`, ); @@ -49,15 +49,22 @@ export class LastSeenService { updateLastSeen(clientMetrics: IClientMetricsEnv[]): void { clientMetrics + .filter( + (clientMetric) => + !this.lastSeenToggles.has( + `${clientMetric.featureName}:${clientMetric.environment}`, + ), + ) .filter( (clientMetric) => clientMetric.yes > 0 || clientMetric.no > 0, ) - .forEach((clientMetric) => - this.lastSeenToggles.add({ + .forEach((clientMetric) => { + const key = `${clientMetric.featureName}:${clientMetric.environment}`; + this.lastSeenToggles.set(key, { featureName: clientMetric.featureName, environment: clientMetric.environment, - }), - ); + }); + }); } destroy(): void {