mirror of
https://github.com/Microsoft/vscode
synced 2024-10-04 02:14:06 +00:00
server: fix socket pipe disconnections not getting detected (#214640)
Fixes #211462
This commit is contained in:
parent
b814ff2c68
commit
dc97013993
|
@ -17,6 +17,15 @@ import { generateUuid } from 'vs/base/common/uuid';
|
|||
import { ClientConnectionEvent, IPCServer } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { ChunkStream, Client, ISocket, Protocol, SocketCloseEvent, SocketCloseEventType, SocketDiagnostics, SocketDiagnosticsEventType } from 'vs/base/parts/ipc/common/ipc.net';
|
||||
|
||||
/**
|
||||
* Maximum time to wait for a 'close' event to fire after the socket stream
|
||||
* ends. For unix domain sockets, the close event may not fire consistently
|
||||
* due to what appears to be a Node.js bug.
|
||||
*
|
||||
* @see https://github.com/microsoft/vscode/issues/211462#issuecomment-2155471996
|
||||
*/
|
||||
const socketEndTimeoutMs = 30_000;
|
||||
|
||||
export class NodeSocket implements ISocket {
|
||||
|
||||
public readonly debugLabel: string;
|
||||
|
@ -51,15 +60,20 @@ export class NodeSocket implements ISocket {
|
|||
};
|
||||
this.socket.on('error', this._errorListener);
|
||||
|
||||
let endTimeoutHandle: NodeJS.Timeout | undefined;
|
||||
this._closeListener = (hadError: boolean) => {
|
||||
this.traceSocketEvent(SocketDiagnosticsEventType.Close, { hadError });
|
||||
this._canWrite = false;
|
||||
if (endTimeoutHandle) {
|
||||
clearTimeout(endTimeoutHandle);
|
||||
}
|
||||
};
|
||||
this.socket.on('close', this._closeListener);
|
||||
|
||||
this._endListener = () => {
|
||||
this.traceSocketEvent(SocketDiagnosticsEventType.NodeEndReceived);
|
||||
this._canWrite = false;
|
||||
endTimeoutHandle = setTimeout(() => socket.destroy(), socketEndTimeoutMs);
|
||||
};
|
||||
this.socket.on('end', this._endListener);
|
||||
}
|
||||
|
|
|
@ -4,13 +4,14 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import assert from 'assert';
|
||||
import sinon from 'sinon';
|
||||
import { EventEmitter } from 'events';
|
||||
import { AddressInfo, connect, createServer, Server, Socket } from 'net';
|
||||
import { tmpdir } from 'os';
|
||||
import { Barrier, timeout } from 'vs/base/common/async';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { ILoadEstimator, PersistentProtocol, Protocol, ProtocolConstants, SocketCloseEvent, SocketDiagnosticsEventType } from 'vs/base/parts/ipc/common/ipc.net';
|
||||
import { createRandomIPCHandle, createStaticIPCHandle, NodeSocket, WebSocketNodeSocket } from 'vs/base/parts/ipc/node/ipc.net';
|
||||
import { flakySuite } from 'vs/base/test/common/testUtils';
|
||||
|
@ -134,7 +135,7 @@ class Ether {
|
|||
|
||||
suite('IPC, Socket Protocol', () => {
|
||||
|
||||
ensureNoDisposablesAreLeakedInTestSuite();
|
||||
const ds = ensureNoDisposablesAreLeakedInTestSuite();
|
||||
|
||||
let ether: Ether;
|
||||
|
||||
|
@ -186,6 +187,26 @@ suite('IPC, Socket Protocol', () => {
|
|||
b.dispose();
|
||||
});
|
||||
|
||||
|
||||
|
||||
test('issue #211462: destroy socket after end timeout', async () => {
|
||||
const socket = new EventEmitter();
|
||||
Object.assign(socket, { destroy: () => socket.emit('close') });
|
||||
const protocol = ds.add(new Protocol(new NodeSocket(socket as Socket)));
|
||||
|
||||
const disposed = sinon.stub();
|
||||
const timers = sinon.useFakeTimers();
|
||||
|
||||
ds.add(toDisposable(() => timers.restore()));
|
||||
ds.add(protocol.onDidDispose(disposed));
|
||||
|
||||
socket.emit('end');
|
||||
assert.ok(!disposed.called);
|
||||
timers.tick(29_999);
|
||||
assert.ok(!disposed.called);
|
||||
timers.tick(1);
|
||||
assert.ok(disposed.called);
|
||||
});
|
||||
});
|
||||
|
||||
suite('PersistentProtocol reconnection', () => {
|
||||
|
|
Loading…
Reference in a new issue