From 42fbfd7e4dd04794e1820b2ff8a2c860885cba5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Fern=C3=A1ndez=20Haro?= Date: Tue, 17 Aug 2021 21:46:54 +0100 Subject: [PATCH] Add debounce to the status observers to reduce unnecessary CPU loops (#108952) --- src/core/server/status/plugins_status.test.ts | 31 +++++++++++++++++-- src/core/server/status/plugins_status.ts | 1 + 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/core/server/status/plugins_status.test.ts b/src/core/server/status/plugins_status.test.ts index a6579069acbc0..b7c0733de728e 100644 --- a/src/core/server/status/plugins_status.test.ts +++ b/src/core/server/status/plugins_status.test.ts @@ -247,7 +247,6 @@ describe('PluginStatusService', () => { subscription.unsubscribe(); expect(statusUpdates).toEqual([ - { a: { level: ServiceStatusLevels.available, summary: 'All dependencies are available' } }, { a: { level: ServiceStatusLevels.degraded, summary: 'a degraded' } }, { a: { level: ServiceStatusLevels.unavailable, summary: 'a unavailable' } }, { a: { level: ServiceStatusLevels.available, summary: 'a available' } }, @@ -274,7 +273,6 @@ describe('PluginStatusService', () => { subscription.unsubscribe(); expect(statusUpdates).toEqual([ - { a: { level: ServiceStatusLevels.available, summary: 'All dependencies are available' } }, { a: { level: ServiceStatusLevels.degraded, summary: 'a degraded' } }, { a: { level: ServiceStatusLevels.unavailable, summary: 'a unavailable' } }, { a: { level: ServiceStatusLevels.available, summary: 'a available' } }, @@ -357,6 +355,35 @@ describe('PluginStatusService', () => { }).toThrowError(); }); + it('debounces plugins custom status registration', async () => { + const service = new PluginsStatusService({ + core$: coreAllAvailable$, + pluginDependencies, + }); + const available: ServiceStatus = { + level: ServiceStatusLevels.available, + summary: 'a available', + }; + + const statusUpdates: Array> = []; + const subscription = service + .getDependenciesStatus$('b') + .subscribe((status) => statusUpdates.push(status)); + + const pluginA$ = new BehaviorSubject(available); + service.set('a', pluginA$); + + expect(statusUpdates).toStrictEqual([]); + + const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); + + // Waiting for the debounce timeout should cut a new update + await delay(25); + subscription.unsubscribe(); + + expect(statusUpdates).toStrictEqual([{ a: available }]); + }); + it('debounces events in quick succession', async () => { const service = new PluginsStatusService({ core$: coreAllAvailable$, diff --git a/src/core/server/status/plugins_status.ts b/src/core/server/status/plugins_status.ts index 6a8ef1081e165..7ef3ddb31d978 100644 --- a/src/core/server/status/plugins_status.ts +++ b/src/core/server/status/plugins_status.ts @@ -76,6 +76,7 @@ export class PluginsStatusService { public getDerivedStatus$(plugin: PluginName): Observable { return this.update$.pipe( + debounceTime(25), // Avoid calling the plugin's custom status logic for every plugin that depends on it. switchMap(() => { // Only go up the dependency tree if any of this plugin's dependencies have a custom status // Helps eliminate memory overhead of creating thousands of Observables unnecessarily.