mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Telemetry] Only send from active window (#123909)
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
a791ed6043
commit
bc6e30d740
3 changed files with 61 additions and 7 deletions
|
@ -186,6 +186,10 @@ export class TelemetryPlugin implements Plugin<TelemetryPluginSetup, TelemetryPl
|
|||
};
|
||||
}
|
||||
|
||||
public stop() {
|
||||
this.telemetrySender?.stop();
|
||||
}
|
||||
|
||||
private getTelemetryServicePublicApis(): TelemetryServicePublicApis {
|
||||
const telemetryService = this.telemetryService!;
|
||||
return {
|
||||
|
|
|
@ -66,6 +66,29 @@ describe('TelemetrySender', () => {
|
|||
});
|
||||
|
||||
describe('shouldSendReport', () => {
|
||||
let hasFocus: jest.SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
hasFocus = jest.spyOn(document, 'hasFocus');
|
||||
hasFocus.mockReturnValue(true); // Return true by default for all tests;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
hasFocus.mockRestore();
|
||||
});
|
||||
|
||||
it('returns false if the page is not visible', async () => {
|
||||
hasFocus.mockReturnValue(false);
|
||||
const telemetryService = mockTelemetryService();
|
||||
telemetryService.getIsOptedIn = jest.fn().mockReturnValue(true);
|
||||
telemetryService.fetchLastReported = jest.fn().mockResolvedValue(Date.now());
|
||||
const telemetrySender = new TelemetrySender(telemetryService);
|
||||
const shouldSendReport = await telemetrySender['shouldSendReport']();
|
||||
expect(shouldSendReport).toBe(false);
|
||||
expect(telemetryService.getIsOptedIn).toBeCalledTimes(0);
|
||||
expect(telemetryService.fetchLastReported).toBeCalledTimes(0);
|
||||
});
|
||||
|
||||
it('returns false whenever optIn is false', async () => {
|
||||
const telemetryService = mockTelemetryService();
|
||||
telemetryService.getIsOptedIn = jest.fn().mockReturnValue(false);
|
||||
|
@ -372,9 +395,11 @@ describe('TelemetrySender', () => {
|
|||
it('calls sendIfDue every 60000 ms', () => {
|
||||
const telemetryService = mockTelemetryService();
|
||||
const telemetrySender = new TelemetrySender(telemetryService);
|
||||
telemetrySender['sendIfDue'] = jest.fn().mockResolvedValue(void 0);
|
||||
telemetrySender.startChecking();
|
||||
expect(setInterval).toBeCalledTimes(1);
|
||||
expect(setInterval).toBeCalledWith(telemetrySender['sendIfDue'], 60000);
|
||||
expect(telemetrySender['sendIfDue']).toHaveBeenCalledTimes(0);
|
||||
jest.advanceTimersByTime(60000);
|
||||
expect(telemetrySender['sendIfDue']).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { Subscription } from 'rxjs';
|
||||
import { fromEvent, interval, merge } from 'rxjs';
|
||||
import { exhaustMap } from 'rxjs/operators';
|
||||
import { LOCALSTORAGE_KEY, PAYLOAD_CONTENT_ENCODING } from '../../common/constants';
|
||||
import { TelemetryService } from './telemetry_service';
|
||||
import { Storage } from '../../../kibana_utils/public';
|
||||
|
@ -16,7 +19,7 @@ export class TelemetrySender {
|
|||
private readonly telemetryService: TelemetryService;
|
||||
private lastReported?: number;
|
||||
private readonly storage: Storage;
|
||||
private intervalId: number = 0; // setInterval returns a positive integer, 0 means no interval is set
|
||||
private sendIfDue$?: Subscription;
|
||||
private retryCount: number = 0;
|
||||
|
||||
static getRetryDelay(retryCount: number) {
|
||||
|
@ -62,11 +65,21 @@ export class TelemetrySender {
|
|||
};
|
||||
|
||||
/**
|
||||
* Using configuration and the lastReported dates, it decides whether a new telemetry report should be sent.
|
||||
* Returns `true` when the page is visible and active in the browser.
|
||||
*/
|
||||
private isActiveWindow = () => {
|
||||
// Using `document.hasFocus()` instead of `document.visibilityState` because the latter may return "visible"
|
||||
// if 2 windows are open side-by-side because they are "technically" visible.
|
||||
return document.hasFocus();
|
||||
};
|
||||
|
||||
/**
|
||||
* Using configuration, page visibility state and the lastReported dates,
|
||||
* it decides whether a new telemetry report should be sent.
|
||||
* @returns `true` if a new report should be sent. `false` otherwise.
|
||||
*/
|
||||
private shouldSendReport = async (): Promise<boolean> => {
|
||||
if (this.telemetryService.canSendTelemetry()) {
|
||||
if (this.isActiveWindow() && this.telemetryService.canSendTelemetry()) {
|
||||
return await this.isReportDue();
|
||||
}
|
||||
|
||||
|
@ -122,8 +135,20 @@ export class TelemetrySender {
|
|||
};
|
||||
|
||||
public startChecking = () => {
|
||||
if (this.intervalId === 0) {
|
||||
this.intervalId = window.setInterval(this.sendIfDue, 60000);
|
||||
if (!this.sendIfDue$) {
|
||||
// Trigger sendIfDue...
|
||||
this.sendIfDue$ = merge(
|
||||
// ... periodically
|
||||
interval(60000),
|
||||
// ... when it regains `focus`
|
||||
fromEvent(window, 'focus') // Using `window` instead of `document` because Chrome only emits on the first one.
|
||||
)
|
||||
.pipe(exhaustMap(this.sendIfDue))
|
||||
.subscribe();
|
||||
}
|
||||
};
|
||||
|
||||
public stop = () => {
|
||||
this.sendIfDue$?.unsubscribe();
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue