mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-18 23:59:43 +01:00
fix: add graceful shutdown path when heapprofile is enabled
This commit is contained in:
@@ -24,6 +24,12 @@ const contentLengthSize: number = Buffer.byteLength(contentLength, 'utf8');
|
|||||||
const blank: number = Buffer.from(' ', 'utf8')[0];
|
const blank: number = Buffer.from(' ', 'utf8')[0];
|
||||||
const backslashR: number = Buffer.from('\r', 'utf8')[0];
|
const backslashR: number = Buffer.from('\r', 'utf8')[0];
|
||||||
const backslashN: number = Buffer.from('\n', 'utf8')[0];
|
const backslashN: number = Buffer.from('\n', 'utf8')[0];
|
||||||
|
const gracefulExitTimeout = 5000;
|
||||||
|
const tsServerExitRequest: Proto.Request = {
|
||||||
|
seq: 0,
|
||||||
|
type: 'request',
|
||||||
|
command: 'exit',
|
||||||
|
};
|
||||||
|
|
||||||
class ProtocolBuffer {
|
class ProtocolBuffer {
|
||||||
|
|
||||||
@@ -207,10 +213,15 @@ function getTssDebugBrk(): string | undefined {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class IpcChildServerProcess extends Disposable implements TsServerProcess {
|
class IpcChildServerProcess extends Disposable implements TsServerProcess {
|
||||||
|
private _killTimeout: NodeJS.Timeout | undefined;
|
||||||
|
private _isShuttingDown = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly _process: child_process.ChildProcess,
|
private readonly _process: child_process.ChildProcess,
|
||||||
|
private readonly _useGracefulShutdown: boolean,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
this._process.once('exit', () => this.clearKillTimeout());
|
||||||
}
|
}
|
||||||
|
|
||||||
write(serverRequest: Proto.Request): void {
|
write(serverRequest: Proto.Request): void {
|
||||||
@@ -230,18 +241,47 @@ class IpcChildServerProcess extends Disposable implements TsServerProcess {
|
|||||||
}
|
}
|
||||||
|
|
||||||
kill(): void {
|
kill(): void {
|
||||||
this._process.kill();
|
if (!this._useGracefulShutdown) {
|
||||||
|
this._process.kill();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._isShuttingDown) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._isShuttingDown = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
this._process.send(tsServerExitRequest);
|
||||||
|
} catch {
|
||||||
|
this._process.kill();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._killTimeout = setTimeout(() => this._process.kill(), gracefulExitTimeout);
|
||||||
|
this._killTimeout.unref?.();
|
||||||
|
}
|
||||||
|
|
||||||
|
private clearKillTimeout(): void {
|
||||||
|
if (this._killTimeout) {
|
||||||
|
clearTimeout(this._killTimeout);
|
||||||
|
this._killTimeout = undefined;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class StdioChildServerProcess extends Disposable implements TsServerProcess {
|
class StdioChildServerProcess extends Disposable implements TsServerProcess {
|
||||||
private readonly _reader: Reader<Proto.Response>;
|
private readonly _reader: Reader<Proto.Response>;
|
||||||
|
private _killTimeout: NodeJS.Timeout | undefined;
|
||||||
|
private _isShuttingDown = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly _process: child_process.ChildProcess,
|
private readonly _process: child_process.ChildProcess,
|
||||||
|
private readonly _useGracefulShutdown: boolean,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this._reader = this._register(new Reader<Proto.Response>(this._process.stdout!));
|
this._reader = this._register(new Reader<Proto.Response>(this._process.stdout!));
|
||||||
|
this._process.once('exit', () => this.clearKillTimeout());
|
||||||
}
|
}
|
||||||
|
|
||||||
write(serverRequest: Proto.Request): void {
|
write(serverRequest: Proto.Request): void {
|
||||||
@@ -262,7 +302,39 @@ class StdioChildServerProcess extends Disposable implements TsServerProcess {
|
|||||||
}
|
}
|
||||||
|
|
||||||
kill(): void {
|
kill(): void {
|
||||||
this._process.kill();
|
if (!this._useGracefulShutdown) {
|
||||||
|
this._process.kill();
|
||||||
|
this._reader.dispose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._isShuttingDown) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._isShuttingDown = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
this._process.stdin?.write(JSON.stringify(tsServerExitRequest) + '\r\n', 'utf8');
|
||||||
|
this._process.stdin?.end();
|
||||||
|
} catch {
|
||||||
|
this._process.kill();
|
||||||
|
this._reader.dispose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._killTimeout = setTimeout(() => {
|
||||||
|
this._process.kill();
|
||||||
|
this._reader.dispose();
|
||||||
|
}, gracefulExitTimeout);
|
||||||
|
this._killTimeout.unref?.();
|
||||||
|
}
|
||||||
|
|
||||||
|
private clearKillTimeout(): void {
|
||||||
|
if (this._killTimeout) {
|
||||||
|
clearTimeout(this._killTimeout);
|
||||||
|
this._killTimeout = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
this._reader.dispose();
|
this._reader.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -290,6 +362,7 @@ export class ElectronServiceProcessFactory implements TsServerProcessFactory {
|
|||||||
const env = generatePatchedEnv(process.env, tsServerPath, !!execPath);
|
const env = generatePatchedEnv(process.env, tsServerPath, !!execPath);
|
||||||
const runtimeArgs = [...args];
|
const runtimeArgs = [...args];
|
||||||
const execArgv = getExecArgv(kind, configuration);
|
const execArgv = getExecArgv(kind, configuration);
|
||||||
|
const useGracefulShutdown = configuration.heapProfile.enabled;
|
||||||
const useIpc = !execPath && version.apiVersion?.gte(API.v460);
|
const useIpc = !execPath && version.apiVersion?.gte(API.v460);
|
||||||
if (useIpc) {
|
if (useIpc) {
|
||||||
runtimeArgs.push('--useNodeIpc');
|
runtimeArgs.push('--useNodeIpc');
|
||||||
@@ -309,6 +382,6 @@ export class ElectronServiceProcessFactory implements TsServerProcessFactory {
|
|||||||
stdio: useIpc ? ['pipe', 'pipe', 'pipe', 'ipc'] : undefined,
|
stdio: useIpc ? ['pipe', 'pipe', 'pipe', 'ipc'] : undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
return useIpc ? new IpcChildServerProcess(childProcess) : new StdioChildServerProcess(childProcess);
|
return useIpc ? new IpcChildServerProcess(childProcess, useGracefulShutdown) : new StdioChildServerProcess(childProcess, useGracefulShutdown);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user