Skip to content

Commit 387b611

Browse files
committed
After a reconnection, let the other party know (again) which messages have been received
1 parent 06fad25 commit 387b611

File tree

2 files changed

+78
-7
lines changed

2 files changed

+78
-7
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -907,6 +907,11 @@ export class PersistentProtocol implements IMessagePassingProtocol {
907907
this._socketWriter.write(toSend[i]);
908908
}
909909
this._recvAckCheck();
910+
911+
// After a reconnection, let the other party know (again) which messages have been received.
912+
// (perhaps the other party didn't receive a previous ACK)
913+
this._incomingAckId = 0;
914+
this._sendAckCheck();
910915
}
911916

912917
public acceptDisconnect(): void {

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

Lines changed: 73 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -90,21 +90,25 @@ class Ether {
9090
return <any>this._b;
9191
}
9292

93-
constructor() {
93+
constructor(
94+
private readonly _wireLatency = 0
95+
) {
9496
this._a = new EtherStream(this, 'a');
9597
this._b = new EtherStream(this, 'b');
9698
this._ab = [];
9799
this._ba = [];
98100
}
99101

100102
public write(from: 'a' | 'b', data: Buffer): void {
101-
if (from === 'a') {
102-
this._ab.push(data);
103-
} else {
104-
this._ba.push(data);
105-
}
103+
setTimeout(() => {
104+
if (from === 'a') {
105+
this._ab.push(data);
106+
} else {
107+
this._ba.push(data);
108+
}
106109

107-
setTimeout(() => this._deliver(), 0);
110+
setTimeout(() => this._deliver(), 0);
111+
}, this._wireLatency);
108112
}
109113

110114
private _deliver(): void {
@@ -365,6 +369,68 @@ suite('PersistentProtocol reconnection', () => {
365369
);
366370
});
367371

372+
test('acks are always sent after a reconnection', async () => {
373+
await runWithFakedTimers(
374+
{
375+
useFakeTimers: true,
376+
useSetImmediate: true,
377+
maxTaskCount: 1000
378+
},
379+
async () => {
380+
381+
const loadEstimator: ILoadEstimator = {
382+
hasHighLoad: () => false
383+
};
384+
const wireLatency = 1000;
385+
const ether = new Ether(wireLatency);
386+
const aSocket = new NodeSocket(ether.a);
387+
const a = new PersistentProtocol(aSocket, null, loadEstimator);
388+
const aMessages = new MessageStream(a);
389+
const bSocket = new NodeSocket(ether.b);
390+
const b = new PersistentProtocol(bSocket, null, loadEstimator);
391+
const bMessages = new MessageStream(b);
392+
393+
// send message a1 to have something unacknowledged
394+
a.send(VSBuffer.fromString('a1'));
395+
assert.strictEqual(a.unacknowledgedCount, 1);
396+
assert.strictEqual(b.unacknowledgedCount, 0);
397+
398+
// read message a1 at B
399+
const a1 = await bMessages.waitForOne();
400+
assert.strictEqual(a1.toString(), 'a1');
401+
assert.strictEqual(a.unacknowledgedCount, 1);
402+
assert.strictEqual(b.unacknowledgedCount, 0);
403+
404+
// wait for B to send an ACK message,
405+
// but resume before A receives it
406+
await timeout(ProtocolConstants.AcknowledgeTime + wireLatency / 2);
407+
assert.strictEqual(a.unacknowledgedCount, 1);
408+
assert.strictEqual(b.unacknowledgedCount, 0);
409+
410+
// simulate complete reconnection
411+
aSocket.dispose();
412+
bSocket.dispose();
413+
const ether2 = new Ether(wireLatency);
414+
const aSocket2 = new NodeSocket(ether2.a);
415+
const bSocket2 = new NodeSocket(ether2.b);
416+
b.beginAcceptReconnection(bSocket2, null);
417+
b.endAcceptReconnection();
418+
a.beginAcceptReconnection(aSocket2, null);
419+
a.endAcceptReconnection();
420+
421+
// wait for quite some time
422+
await timeout(2 * ProtocolConstants.AcknowledgeTime + wireLatency);
423+
assert.strictEqual(a.unacknowledgedCount, 0);
424+
assert.strictEqual(b.unacknowledgedCount, 0);
425+
426+
aMessages.dispose();
427+
bMessages.dispose();
428+
a.dispose();
429+
b.dispose();
430+
}
431+
);
432+
});
433+
368434
test('writing can be paused', async () => {
369435
await runWithFakedTimers({ useFakeTimers: true, maxTaskCount: 100 }, async () => {
370436
const loadEstimator: ILoadEstimator = {

0 commit comments

Comments
 (0)