Skip to content

Commit

Permalink
Add debounce to the status observers to reduce unnecessary CPU loops (#…
Browse files Browse the repository at this point in the history
…108952) (#108998)

Co-authored-by: Alejandro Fernández Haro <alejandro.haro@elastic.co>
  • Loading branch information
kibanamachine and afharo committed Aug 17, 2021
1 parent 56c1a6d commit 62cad9b
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 2 deletions.
31 changes: 29 additions & 2 deletions src/core/server/status/plugins_status.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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' } },
Expand All @@ -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' } },
Expand Down Expand Up @@ -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<Record<string, ServiceStatus>> = [];
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$,
Expand Down
1 change: 1 addition & 0 deletions src/core/server/status/plugins_status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ export class PluginsStatusService {

public getDerivedStatus$(plugin: PluginName): Observable<ServiceStatus> {
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.
Expand Down

0 comments on commit 62cad9b

Please sign in to comment.