提交 fb757bcc 编写于 作者: J Johannes Rieken

add extension host heart beat and log telemetry event when ext host goes dark, #14758

上级 f62a5db2
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import Event, { Emitter } from 'vs/base/common/event';
export class WatchDog {
private _timeout: number;
private _threshold: number;
private _onAlert = new Emitter<this>();
private _handle: number;
private _missed: number;
private _lastSignal: number;
constructor(timeout: number, threshold: number) {
this._timeout = timeout;
this._threshold = threshold;
}
dispose(): void {
this.stop();
}
get onAlert(): Event<this> {
return this._onAlert.event;
}
start(): void {
this.reset();
this._handle = setInterval(this._check.bind(this), this._timeout * 1.5);
}
stop(): void {
clearInterval(this._handle);
}
reset(): void {
this._lastSignal = Date.now();
this._missed = 0;
}
private _check(): void {
if ((Date.now() - this._lastSignal) > this._timeout) {
this._missed += 1;
if (this._missed > this._threshold) {
this._onAlert.fire(this);
this._missed = 0;
}
}
}
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import { WatchDog } from 'vs/base/common/watchDog';
suite('WatchDog', function () {
test('start/stop', function (done) {
const dog = new WatchDog(10, 1);
dog.onAlert(e => {
dog.stop();
assert.ok(e === dog);
done();
});
dog.start();
});
});
......@@ -25,6 +25,7 @@ import { ReloadWindowAction } from 'vs/workbench/electron-browser/actions';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
import Event, { Emitter } from 'vs/base/common/event';
import { WatchDog } from 'vs/base/common/watchDog';
import { createQueuedSender, IQueuedSender } from 'vs/base/node/processes';
import { IInitData, IInitConfiguration } from 'vs/workbench/api/node/extHost.protocol';
import { MainProcessExtensionService } from 'vs/workbench/api/node/mainThreadExtensionService';
......@@ -55,6 +56,8 @@ export class ExtensionHostProcessWorker {
private isExtensionDevelopmentTestFromCli: boolean;
private isExtensionDevelopmentDebugging: boolean;
private extHostWatchDog = new WatchDog(250, 4);
private _onMessage = new Emitter<any>();
public get onMessage(): Event<any> {
return this._onMessage.event;
......@@ -110,6 +113,29 @@ export class ExtensionHostProcessWorker {
// Initialize extension host process with hand shakes
this.initializeExtensionHostProcess = this.doInitializeExtensionHostProcess(opts);
// Check how well the extension host is doing
if (this.environmentService.isBuilt) {
this.initializeExtensionHostProcess.done(() => {
this.extHostWatchDog.start();
this.extHostWatchDog.onAlert(() => {
this.extHostWatchDog.stop();
// log the identifiers of those extensions that
// have code and are loaded in the extension host
this.extensionService.getExtensions().then(extensions => {
const ids: string[] = [];
for (const ext of extensions) {
if (ext.main) {
ids.push(ext.id);
}
}
this.telemetryService.publicLog('extHostUnresponsive', ids);
});
});
});
}
}
public get messagingProtocol(): IMessagePassingProtocol {
......@@ -191,6 +217,12 @@ export class ExtensionHostProcessWorker {
return true;
}
// Heartbeat message
if (msg === '__$heartbeat') {
this.extHostWatchDog.reset();
return false;
}
// Support logging from extension host
if (msg && (<ILogEntry>msg).type === '__$console') {
this.logExtensionHostMessage(<ILogEntry>msg);
......@@ -339,4 +371,4 @@ export class ExtensionHostProcessWorker {
event.veto(TPromise.timeout(100 /* wait a bit for IPC to get delivered */).then(() => false));
}
}
}
\ No newline at end of file
}
......@@ -106,6 +106,12 @@ function connectToRenderer(): TPromise<IRendererConnection> {
stats.length = 0;
}, 1000);
// Send heartbeat
setInterval(function () {
queuedSender.send('__$heartbeat');
}, 250);
// Tell the outside that we are initialized
queuedSender.send('initialized');
......@@ -121,4 +127,4 @@ connectToRenderer().then(renderer => {
const extensionHostMain = new ExtensionHostMain(renderer.remoteCom, renderer.initData);
onTerminate = () => extensionHostMain.terminate();
return extensionHostMain.start();
}).done(null, err => console.error(err));
\ No newline at end of file
}).done(null, err => console.error(err));
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册