Skip to content

Commit b83d48f

Browse files
[SignalR][TS client] Send ping on connection start (#43695)
1 parent 03ad638 commit b83d48f

File tree

3 files changed

+66
-57
lines changed

3 files changed

+66
-57
lines changed

src/SignalR/clients/ts/FunctionalTests/ts/HubConnectionTests.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,13 @@ describe("hubConnection", () => {
376376
try {
377377
await hubConnection.start();
378378
} catch (error) {
379-
expect(error!.message).toEqual(expectedErrorMessage);
379+
if (error!.message.includes("404")) {
380+
// SSE can race with the connection closing and the initial ping being successful or failing with a 404.
381+
// LongPolling doesn't have pings and WebSockets is a synchronous API over a single HTTP request so it doesn't have the same issues
382+
expect(error!.message).toEqual("No Connection with that ID: Status code '404'");
383+
} else {
384+
expect(error!.message).toEqual(expectedErrorMessage);
385+
}
380386
closePromise.resolve();
381387
}
382388
await closePromise;

src/SignalR/clients/ts/signalr/src/HubConnection.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,10 @@ export class HubConnection {
235235
// eslint-disable-next-line @typescript-eslint/no-throw-literal
236236
throw this._stopDuringStartError;
237237
}
238+
239+
if (!this.connection.features.inherentKeepAlive) {
240+
await this._sendMessage(this._cachedPingMessage);
241+
}
238242
} catch (e) {
239243
this._logger.log(LogLevel.Debug, `Hub handshake failed with error '${e}' during start(). Stopping HubConnection.`);
240244

src/SignalR/clients/ts/signalr/tests/HubConnection.test.ts

Lines changed: 55 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ describe("HubConnection", () => {
3131
const hubConnection = createHubConnection(connection, logger);
3232
try {
3333
await hubConnection.start();
34-
expect(connection.sentData.length).toBe(1);
34+
expect(connection.sentData.length).toBe(2);
3535
expect(JSON.parse(connection.sentData[0])).toEqual({
3636
protocol: "json",
3737
version: 1,
@@ -448,7 +448,7 @@ describe("HubConnection", () => {
448448
const subject = new Subject();
449449
const invokePromise = hubConnection.invoke("testMethod", "arg", subject);
450450

451-
expect(JSON.parse(connection.sentData[1])).toEqual({
451+
expect(JSON.parse(connection.sentData[2])).toEqual({
452452
arguments: ["arg"],
453453
invocationId: "1",
454454
streamIds: ["0"],
@@ -460,7 +460,7 @@ describe("HubConnection", () => {
460460
await new Promise<void>((resolve) => {
461461
setTimeout(resolve, 50);
462462
});
463-
expect(JSON.parse(connection.sentData[2])).toEqual({
463+
expect(JSON.parse(connection.sentData[3])).toEqual({
464464
invocationId: "0",
465465
item: "item numero uno",
466466
type: MessageType.StreamItem,
@@ -485,7 +485,7 @@ describe("HubConnection", () => {
485485
const subject = new Subject();
486486
await hubConnection.send("testMethod", "arg", subject);
487487

488-
expect(JSON.parse(connection.sentData[1])).toEqual({
488+
expect(JSON.parse(connection.sentData[2])).toEqual({
489489
arguments: ["arg"],
490490
streamIds: ["0"],
491491
target: "testMethod",
@@ -496,7 +496,7 @@ describe("HubConnection", () => {
496496
await new Promise<void>((resolve) => {
497497
setTimeout(resolve, 50);
498498
});
499-
expect(JSON.parse(connection.sentData[2])).toEqual({
499+
expect(JSON.parse(connection.sentData[3])).toEqual({
500500
invocationId: "0",
501501
item: "item numero uno",
502502
type: MessageType.StreamItem,
@@ -528,7 +528,7 @@ describe("HubConnection", () => {
528528
},
529529
});
530530

531-
expect(JSON.parse(connection.sentData[1])).toEqual({
531+
expect(JSON.parse(connection.sentData[2])).toEqual({
532532
arguments: ["arg"],
533533
invocationId: "1",
534534
streamIds: ["0"],
@@ -540,7 +540,7 @@ describe("HubConnection", () => {
540540
await new Promise<void>((resolve) => {
541541
setTimeout(resolve, 50);
542542
});
543-
expect(JSON.parse(connection.sentData[2])).toEqual({
543+
expect(JSON.parse(connection.sentData[3])).toEqual({
544544
invocationId: "0",
545545
item: "item numero uno",
546546
type: MessageType.StreamItem,
@@ -1102,10 +1102,10 @@ describe("HubConnection", () => {
11021102
// async here to guarantee the sent message is written
11031103
await delayUntil(1);
11041104

1105-
expect(connection.parsedSentData.length).toEqual(2);
1106-
expect(connection.parsedSentData[1].type).toEqual(3);
1107-
expect(connection.parsedSentData[1].result).toEqual(10);
1108-
expect(connection.parsedSentData[1].invocationId).toEqual("1");
1105+
expect(connection.parsedSentData.length).toEqual(3);
1106+
expect(connection.parsedSentData[2].type).toEqual(3);
1107+
expect(connection.parsedSentData[2].result).toEqual(10);
1108+
expect(connection.parsedSentData[2].invocationId).toEqual("1");
11091109
} finally {
11101110
await hubConnection.stop();
11111111
}
@@ -1133,10 +1133,10 @@ describe("HubConnection", () => {
11331133
// async here to guarantee the sent message is written
11341134
await delayUntil(1);
11351135

1136-
expect(connection.parsedSentData.length).toEqual(2);
1137-
expect(connection.parsedSentData[1].type).toEqual(3);
1138-
expect(connection.parsedSentData[1].result).toBeNull();
1139-
expect(connection.parsedSentData[1].invocationId).toEqual("1");
1136+
expect(connection.parsedSentData.length).toEqual(3);
1137+
expect(connection.parsedSentData[2].type).toEqual(3);
1138+
expect(connection.parsedSentData[2].result).toBeNull();
1139+
expect(connection.parsedSentData[2].invocationId).toEqual("1");
11401140
} finally {
11411141
await hubConnection.stop();
11421142
}
@@ -1166,10 +1166,10 @@ describe("HubConnection", () => {
11661166
// async here to guarantee the sent message is written
11671167
await delayUntil(1);
11681168

1169-
expect(connection.parsedSentData.length).toEqual(2);
1170-
expect(connection.parsedSentData[1].type).toEqual(3);
1171-
expect(connection.parsedSentData[1].result).toEqual(13);
1172-
expect(connection.parsedSentData[1].invocationId).toEqual("1");
1169+
expect(connection.parsedSentData.length).toEqual(3);
1170+
expect(connection.parsedSentData[2].type).toEqual(3);
1171+
expect(connection.parsedSentData[2].result).toEqual(13);
1172+
expect(connection.parsedSentData[2].invocationId).toEqual("1");
11731173
} finally {
11741174
await hubConnection.stop();
11751175
}
@@ -1197,10 +1197,10 @@ describe("HubConnection", () => {
11971197
// async here to guarantee the sent message is written
11981198
await delayUntil(1);
11991199

1200-
expect(connection.parsedSentData.length).toEqual(2);
1201-
expect(connection.parsedSentData[1].type).toEqual(3);
1202-
expect(connection.parsedSentData[1].error).toEqual("Error: from callback");
1203-
expect(connection.parsedSentData[1].invocationId).toEqual("1");
1200+
expect(connection.parsedSentData.length).toEqual(3);
1201+
expect(connection.parsedSentData[2].type).toEqual(3);
1202+
expect(connection.parsedSentData[2].error).toEqual("Error: from callback");
1203+
expect(connection.parsedSentData[2].invocationId).toEqual("1");
12041204
} finally {
12051205
await hubConnection.stop();
12061206
}
@@ -1229,10 +1229,10 @@ describe("HubConnection", () => {
12291229
// async here to guarantee the sent message is written
12301230
await delayUntil(1);
12311231

1232-
expect(connection.parsedSentData.length).toEqual(2);
1233-
expect(connection.parsedSentData[1].type).toEqual(3);
1234-
expect(connection.parsedSentData[1].error).toEqual('Client provided multiple results.');
1235-
expect(connection.parsedSentData[1].invocationId).toEqual("1");
1232+
expect(connection.parsedSentData.length).toEqual(3);
1233+
expect(connection.parsedSentData[2].type).toEqual(3);
1234+
expect(connection.parsedSentData[2].error).toEqual('Client provided multiple results.');
1235+
expect(connection.parsedSentData[2].invocationId).toEqual("1");
12361236
} finally {
12371237
await hubConnection.stop();
12381238
}
@@ -1261,11 +1261,11 @@ describe("HubConnection", () => {
12611261
// async here to guarantee the sent message is written
12621262
await delayUntil(1);
12631263

1264-
expect(connection.parsedSentData.length).toEqual(2);
1265-
expect(connection.parsedSentData[1].type).toEqual(3);
1266-
expect(connection.parsedSentData[1].error).toEqual("Error: from callback");
1267-
expect(connection.parsedSentData[1].result).toBeUndefined();
1268-
expect(connection.parsedSentData[1].invocationId).toEqual("1");
1264+
expect(connection.parsedSentData.length).toEqual(3);
1265+
expect(connection.parsedSentData[2].type).toEqual(3);
1266+
expect(connection.parsedSentData[2].error).toEqual("Error: from callback");
1267+
expect(connection.parsedSentData[2].result).toBeUndefined();
1268+
expect(connection.parsedSentData[2].invocationId).toEqual("1");
12691269
} finally {
12701270
await hubConnection.stop();
12711271
}
@@ -1294,11 +1294,11 @@ describe("HubConnection", () => {
12941294
// async here to guarantee the sent message is written
12951295
await delayUntil(1);
12961296

1297-
expect(connection.parsedSentData.length).toEqual(2);
1298-
expect(connection.parsedSentData[1].type).toEqual(3);
1299-
expect(connection.parsedSentData[1].result).toEqual(3);
1300-
expect(connection.parsedSentData[1].error).toBeUndefined();
1301-
expect(connection.parsedSentData[1].invocationId).toEqual("1");
1297+
expect(connection.parsedSentData.length).toEqual(3);
1298+
expect(connection.parsedSentData[2].type).toEqual(3);
1299+
expect(connection.parsedSentData[2].result).toEqual(3);
1300+
expect(connection.parsedSentData[2].error).toBeUndefined();
1301+
expect(connection.parsedSentData[2].invocationId).toEqual("1");
13021302
} finally {
13031303
await hubConnection.stop();
13041304
}
@@ -1326,10 +1326,10 @@ describe("HubConnection", () => {
13261326
// async here to guarantee the sent message is written
13271327
await delayUntil(1);
13281328

1329-
expect(connection.parsedSentData.length).toEqual(2);
1330-
expect(connection.parsedSentData[1].type).toEqual(3);
1331-
expect(connection.parsedSentData[1].error).toEqual("Client didn't provide a result.");
1332-
expect(connection.parsedSentData[1].invocationId).toEqual("1");
1329+
expect(connection.parsedSentData.length).toEqual(3);
1330+
expect(connection.parsedSentData[2].type).toEqual(3);
1331+
expect(connection.parsedSentData[2].error).toEqual("Client didn't provide a result.");
1332+
expect(connection.parsedSentData[2].invocationId).toEqual("1");
13331333
} finally {
13341334
await hubConnection.stop();
13351335
}
@@ -1355,10 +1355,10 @@ describe("HubConnection", () => {
13551355
// async here to guarantee the sent message is written
13561356
await delayUntil(1);
13571357

1358-
expect(connection.parsedSentData.length).toEqual(2);
1359-
expect(connection.parsedSentData[1].type).toEqual(3);
1360-
expect(connection.parsedSentData[1].error).toEqual("Client didn't provide a result.");
1361-
expect(connection.parsedSentData[1].invocationId).toEqual("1");
1358+
expect(connection.parsedSentData.length).toEqual(3);
1359+
expect(connection.parsedSentData[2].type).toEqual(3);
1360+
expect(connection.parsedSentData[2].error).toEqual("Client didn't provide a result.");
1361+
expect(connection.parsedSentData[2].invocationId).toEqual("1");
13621362
} finally {
13631363
await hubConnection.stop();
13641364
}
@@ -1386,7 +1386,7 @@ describe("HubConnection", () => {
13861386
// async here to guarantee the sent message is written
13871387
await delayUntil(1);
13881388

1389-
expect(connection.parsedSentData.length).toEqual(1);
1389+
expect(connection.parsedSentData.length).toEqual(2);
13901390
} finally {
13911391
await hubConnection.stop();
13921392
}
@@ -1405,9 +1405,9 @@ describe("HubConnection", () => {
14051405

14061406
hubConnection.stream("testStream", "arg", 42);
14071407

1408-
// Verify the message is sent (+ handshake)
1409-
expect(connection.sentData.length).toBe(2);
1410-
expect(JSON.parse(connection.sentData[1])).toEqual({
1408+
// Verify the message is sent (+ handshake + ping)
1409+
expect(connection.sentData.length).toBe(3);
1410+
expect(JSON.parse(connection.sentData[2])).toEqual({
14111411
arguments: [
14121412
"arg",
14131413
42,
@@ -1416,9 +1416,6 @@ describe("HubConnection", () => {
14161416
target: "testStream",
14171417
type: MessageType.StreamInvocation,
14181418
});
1419-
1420-
// Close the connection
1421-
await hubConnection.stop();
14221419
} finally {
14231420
await hubConnection.stop();
14241421
}
@@ -1592,10 +1589,10 @@ describe("HubConnection", () => {
15921589
expect(observer.itemsReceived).toEqual([1]);
15931590

15941591
// Close message sent asynchronously so we need to wait
1595-
await delayUntil(1000, () => connection.sentData.length === 3);
1592+
await delayUntil(1000, () => connection.sentData.length === 4);
15961593
// Verify the cancel is sent (+ handshake)
1597-
expect(connection.sentData.length).toBe(3);
1598-
expect(JSON.parse(connection.sentData[2])).toEqual({
1594+
expect(connection.sentData.length).toBe(4);
1595+
expect(JSON.parse(connection.sentData[3])).toEqual({
15991596
invocationId: connection.lastInvocationId,
16001597
type: MessageType.CancelInvocation,
16011598
});
@@ -1830,7 +1827,9 @@ class TestProtocol implements IHubProtocol {
18301827
}
18311828

18321829
public writeMessage(message: HubMessage): any {
1833-
1830+
if (message.type === 6) {
1831+
return "{\"type\": 6}" + TextMessageFormat.RecordSeparator;
1832+
}
18341833
}
18351834
}
18361835

0 commit comments

Comments
 (0)