Bug 1611817 - Fix race condition in DevTools shutdown and stopProfilerAndDiscardProfile; r=julienw

This race condition is really only exposed in automated testing, but it
was making the DevTools performance-new mochitests intermittent.

The race looks like this:

* stopProfilerAndDiscardProfiler() request
* perf actor process the request
* The gecko profiler sends an event notifying that the profiler stopped
* DevTools updates the UI upon receiving the event
* The test suite sees the UI update, and triggers a close of DevTools
* Error: Connection closed, pending request
* stopProfilerAndDiscardProfiler still hasn't sent the response yet

This patch fixes it by not throwing an error if the panel is already destroyed.

Differential Revision: https://phabricator.services.mozilla.com/D65150

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Greg Tatum 2020-03-09 14:57:05 +00:00
Родитель 806c8be4d6
Коммит 68c5d4cc04
3 изменённых файлов: 22 добавлений и 2 удалений

Просмотреть файл

@ -15,7 +15,8 @@ export interface PanelWindow {
gToolbox?: any;
gInit(perfFront: PerfFront, preferenceFront: PageContext): void;
gDestroy(): void;
gReportReady?(): void
gReportReady?(): void;
gIsPanelDestroyed?: boolean;
}
/**

Просмотреть файл

@ -56,6 +56,7 @@ class PerformancePanel {
*/
async _doOpen() {
this.panelWin.gToolbox = this.toolbox;
this.panelWin.gIsPanelDestroyed = false;
const perfFront = await this.target.client.mainRoot.getFront("perf");
@ -82,6 +83,7 @@ class PerformancePanel {
this.panelWin.gDestroy();
this.emit("destroyed");
this._destroyed = true;
this.panelWin.gIsPanelDestroyed = true;
}
}

Просмотреть файл

@ -21,6 +21,7 @@ const {
* @typedef {import("../@types/perf").RecordingState} RecordingState
* @typedef {import("../@types/perf").InitializeStoreValues} InitializeStoreValues
* @typedef {import("../@types/perf").Presets} Presets
* @typedef {import("../@types/perf").PanelWindow} PanelWindow
*/
/**
@ -230,6 +231,22 @@ exports.stopProfilerAndDiscardProfile = () => {
return async (dispatch, getState) => {
const perfFront = selectors.getPerfFront(getState());
dispatch(changeRecordingState("request-to-stop-profiler"));
perfFront.stopProfilerAndDiscardProfile();
try {
await perfFront.stopProfilerAndDiscardProfile();
} catch (error) {
/** @type {any} */
const anyWindow = window;
/** @type {PanelWindow} - Coerce the window into the PanelWindow. */
const { gIsPanelDestroyed } = anyWindow;
if (gIsPanelDestroyed) {
// This error is most likely "Connection closed, pending request" as the
// command can race with closing the panel. Do not report an error. It's
// most likely fine.
} else {
throw error;
}
}
};
};