Skip to content

Commit 2c9f5fe

Browse files
committed
Emit onSocketTimeout at most once every 20s
1 parent 11d880e commit 2c9f5fe

File tree

2 files changed

+67
-2
lines changed

2 files changed

+67
-2
lines changed

src/vs/base/parts/ipc/common/ipc.net.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,7 @@ export class PersistentProtocol implements IMessagePassingProtocol {
778778
private _incomingAckTimeout: any | null;
779779

780780
private _lastReplayRequestTime: number;
781+
private _lastSocketTimeoutTime: number;
781782

782783
private _socket: ISocket;
783784
private _socketWriter: ProtocolWriter;
@@ -819,6 +820,7 @@ export class PersistentProtocol implements IMessagePassingProtocol {
819820
this._incomingAckTimeout = null;
820821

821822
this._lastReplayRequestTime = 0;
823+
this._lastSocketTimeoutTime = Date.now();
822824

823825
this._socketDisposables = [];
824826
this._socket = socket;
@@ -887,6 +889,7 @@ export class PersistentProtocol implements IMessagePassingProtocol {
887889
this._socket.dispose();
888890

889891
this._lastReplayRequestTime = 0;
892+
this._lastSocketTimeoutTime = Date.now();
890893

891894
this._socket = socket;
892895
this._socketWriter = new ProtocolWriter(this._socket);
@@ -1063,26 +1066,36 @@ export class PersistentProtocol implements IMessagePassingProtocol {
10631066
const oldestUnacknowledgedMsg = this._outgoingUnackMsg.peek()!;
10641067
const timeSinceOldestUnacknowledgedMsg = Date.now() - oldestUnacknowledgedMsg.writtenTime;
10651068
const timeSinceLastReceivedSomeData = Date.now() - this._socketReader.lastReadTime;
1069+
const timeSinceLastTimeout = Date.now() - this._lastSocketTimeoutTime;
10661070

10671071
if (
10681072
timeSinceOldestUnacknowledgedMsg >= ProtocolConstants.TimeoutTime
10691073
&& timeSinceLastReceivedSomeData >= ProtocolConstants.TimeoutTime
1074+
&& timeSinceLastTimeout >= ProtocolConstants.TimeoutTime
10701075
) {
10711076
// It's been a long time since our sent message was acknowledged
10721077
// and a long time since we received some data
10731078

10741079
// But this might be caused by the event loop being busy and failing to read messages
10751080
if (!this._loadEstimator.hasHighLoad()) {
10761081
// Trash the socket
1082+
this._lastSocketTimeoutTime = Date.now();
10771083
this._onSocketTimeout.fire(undefined);
10781084
return;
10791085
}
10801086
}
10811087

1088+
const minimumTimeUntilTimeout = Math.max(
1089+
ProtocolConstants.TimeoutTime - timeSinceOldestUnacknowledgedMsg,
1090+
ProtocolConstants.TimeoutTime - timeSinceLastReceivedSomeData,
1091+
ProtocolConstants.TimeoutTime - timeSinceLastTimeout,
1092+
500
1093+
);
1094+
10821095
this._outgoingAckTimeout = setTimeout(() => {
10831096
this._outgoingAckTimeout = null;
10841097
this._recvAckCheck();
1085-
}, Math.max(ProtocolConstants.TimeoutTime - timeSinceOldestUnacknowledgedMsg, 500));
1098+
}, minimumTimeUntilTimeout);
10861099
}
10871100

10881101
private _sendAck(): void {

src/vs/base/parts/ipc/test/node/ipc.net.test.ts

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { createServer, Socket } from 'net';
99
import { tmpdir } from 'os';
1010
import { Barrier, timeout } from 'vs/base/common/async';
1111
import { VSBuffer } from 'vs/base/common/buffer';
12-
import { Emitter } from 'vs/base/common/event';
12+
import { Emitter, Event } from 'vs/base/common/event';
1313
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
1414
import { ILoadEstimator, PersistentProtocol, Protocol, ProtocolConstants, SocketCloseEvent, SocketDiagnosticsEventType } from 'vs/base/parts/ipc/common/ipc.net';
1515
import { createRandomIPCHandle, createStaticIPCHandle, NodeSocket, WebSocketNodeSocket } from 'vs/base/parts/ipc/node/ipc.net';
@@ -431,6 +431,58 @@ suite('PersistentProtocol reconnection', () => {
431431
);
432432
});
433433

434+
test('onSocketTimeout is emitted at most once every 20s', async () => {
435+
await runWithFakedTimers(
436+
{
437+
useFakeTimers: true,
438+
useSetImmediate: true,
439+
maxTaskCount: 1000
440+
},
441+
async () => {
442+
443+
const loadEstimator: ILoadEstimator = {
444+
hasHighLoad: () => false
445+
};
446+
const ether = new Ether();
447+
const aSocket = new NodeSocket(ether.a);
448+
const a = new PersistentProtocol(aSocket, null, loadEstimator);
449+
const aMessages = new MessageStream(a);
450+
const bSocket = new NodeSocket(ether.b);
451+
const b = new PersistentProtocol(bSocket, null, loadEstimator);
452+
const bMessages = new MessageStream(b);
453+
454+
// never receive acks
455+
b.pauseSocketWriting();
456+
457+
// send message a1 to have something unacknowledged
458+
a.send(VSBuffer.fromString('a1'));
459+
460+
// wait for the first timeout to fire
461+
await Event.toPromise(a.onSocketTimeout);
462+
463+
let timeoutFiredAgain = false;
464+
const timeoutListener = a.onSocketTimeout(() => {
465+
timeoutFiredAgain = true;
466+
});
467+
468+
// send more messages
469+
a.send(VSBuffer.fromString('a2'));
470+
a.send(VSBuffer.fromString('a3'));
471+
472+
// wait for 10s
473+
await timeout(ProtocolConstants.TimeoutTime / 2);
474+
475+
assert.strictEqual(timeoutFiredAgain, false);
476+
477+
timeoutListener.dispose();
478+
aMessages.dispose();
479+
bMessages.dispose();
480+
a.dispose();
481+
b.dispose();
482+
}
483+
);
484+
});
485+
434486
test('writing can be paused', async () => {
435487
await runWithFakedTimers({ useFakeTimers: true, maxTaskCount: 100 }, async () => {
436488
const loadEstimator: ILoadEstimator = {

0 commit comments

Comments
 (0)