fix hanging stdio servers (#1200)
Co-authored-by: Johnny Santos <johnnyadsantos@gmail.com> Co-authored-by: TomasRup <tomasr@wix.com>
This commit is contained in:
parent
5aaf6ee67e
commit
ace9b62d3c
1 changed files with 220 additions and 47 deletions
|
|
@ -91,7 +91,6 @@ export function getDefaultEnvironment(): Record<string, string> {
|
|||
*/
|
||||
export class StdioClientTransport implements Transport {
|
||||
private _process?: ChildProcess;
|
||||
private _abortController: AbortController = new AbortController();
|
||||
private _readBuffer: ReadBuffer = new ReadBuffer();
|
||||
private _serverParams: StdioServerParameters;
|
||||
private _stderrStream: PassThrough | null = null;
|
||||
|
|
@ -126,18 +125,11 @@ export class StdioClientTransport implements Transport {
|
|||
},
|
||||
stdio: ['pipe', 'pipe', this._serverParams.stderr ?? 'inherit'],
|
||||
shell: false,
|
||||
signal: this._abortController.signal,
|
||||
windowsHide: process.platform === 'win32' && isElectron(),
|
||||
cwd: this._serverParams.cwd
|
||||
});
|
||||
|
||||
this._process.on('error', error => {
|
||||
if (error.name === 'AbortError') {
|
||||
// Expected when close() is called.
|
||||
this.onclose?.();
|
||||
return;
|
||||
}
|
||||
|
||||
reject(error);
|
||||
this.onerror?.(error);
|
||||
});
|
||||
|
|
@ -210,8 +202,43 @@ export class StdioClientTransport implements Transport {
|
|||
}
|
||||
|
||||
async close(): Promise<void> {
|
||||
this._abortController.abort();
|
||||
this._process = undefined;
|
||||
if (this._process) {
|
||||
const processToClose = this._process;
|
||||
this._process = undefined;
|
||||
|
||||
const closePromise = new Promise<void>(resolve => {
|
||||
processToClose.once('close', () => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
try {
|
||||
processToClose.stdin?.end();
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
|
||||
await Promise.race([closePromise, new Promise(resolve => setTimeout(resolve, 2_000).unref())]);
|
||||
|
||||
if (processToClose.exitCode === null) {
|
||||
try {
|
||||
processToClose.kill('SIGTERM');
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
|
||||
await Promise.race([closePromise, new Promise(resolve => setTimeout(resolve, 2_000).unref())]);
|
||||
}
|
||||
|
||||
if (processToClose.exitCode === null) {
|
||||
try {
|
||||
processToClose.kill('SIGKILL');
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this._readBuffer.clear();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue