Skip to content

Commit dd3771f

Browse files
[SignalR TS] Ignore user errors from stream callbacks (#34136)
1 parent 1b1dd11 commit dd3771f

File tree

3 files changed

+72
-3
lines changed

3 files changed

+72
-3
lines changed

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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { ILogger, LogLevel } from "./ILogger";
88
import { IRetryPolicy } from "./IRetryPolicy";
99
import { IStreamResult } from "./Stream";
1010
import { Subject } from "./Subject";
11-
import { Arg } from "./Utils";
11+
import { Arg, getErrorString } from "./Utils";
1212

1313
const DEFAULT_TIMEOUT_IN_MS: number = 30 * 1000;
1414
const DEFAULT_PING_INTERVAL_IN_MS: number = 15 * 1000;
@@ -544,7 +544,11 @@ export class HubConnection {
544544
if (message.type === MessageType.Completion) {
545545
delete this._callbacks[message.invocationId];
546546
}
547-
callback(message);
547+
try {
548+
callback(message);
549+
} catch (e) {
550+
this._logger.log(LogLevel.Error, `Stream callback threw error: ${getErrorString(e)}`);
551+
}
548552
}
549553
break;
550554
}
@@ -830,7 +834,11 @@ export class HubConnection {
830834
Object.keys(callbacks)
831835
.forEach((key) => {
832836
const callback = callbacks[key];
833-
callback(null, error);
837+
try {
838+
callback(null, error);
839+
} catch (e) {
840+
this._logger.log(LogLevel.Error, `Stream 'error' callback called with '${error}' threw error: ${getErrorString(e)}`);
841+
}
834842
});
835843
}
836844

src/SignalR/clients/ts/signalr/src/Utils.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,3 +266,13 @@ function getRuntime(): string {
266266
return "Browser";
267267
}
268268
}
269+
270+
/** @private */
271+
export function getErrorString(e: any): string {
272+
if (e.stack) {
273+
return e.stack;
274+
} else if (e.message) {
275+
return e.message;
276+
}
277+
return `${e}`;
278+
}

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

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1190,6 +1190,57 @@ describe("HubConnection", () => {
11901190
}
11911191
});
11921192
});
1193+
1194+
it("ignores error from 'next' and 'complete' function", async () => {
1195+
await VerifyLogger.run(async (logger) => {
1196+
const connection = new TestConnection();
1197+
const hubConnection = createHubConnection(connection, logger);
1198+
try {
1199+
await hubConnection.start();
1200+
1201+
hubConnection.stream("testMethod")
1202+
.subscribe({
1203+
next: (_item) => {
1204+
throw new Error("from next");
1205+
},
1206+
error: (_e) => {},
1207+
complete: () => {
1208+
throw new Error("from complete");
1209+
}
1210+
});
1211+
1212+
connection.receive({ type: MessageType.StreamItem, invocationId: connection.lastInvocationId, item: 1 });
1213+
1214+
connection.receive({ type: MessageType.Completion, invocationId: connection.lastInvocationId });
1215+
} finally {
1216+
await hubConnection.stop();
1217+
}
1218+
}, /Stream callback threw error: Error: from complete/,
1219+
/Stream callback threw error: Error: from next/);
1220+
});
1221+
1222+
it("ignores error from 'error' function", async () => {
1223+
await VerifyLogger.run(async (logger) => {
1224+
const connection = new TestConnection();
1225+
const hubConnection = createHubConnection(connection, logger);
1226+
try {
1227+
await hubConnection.start();
1228+
1229+
hubConnection.stream("testMethod")
1230+
.subscribe({
1231+
next: (_item) => {},
1232+
error: (_e) => {
1233+
throw new Error("from error");
1234+
},
1235+
complete: () => {}
1236+
});
1237+
1238+
connection.receive({ type: MessageType.StreamItem, invocationId: connection.lastInvocationId, item: 1 });
1239+
} finally {
1240+
await hubConnection.stop();
1241+
}
1242+
}, /Stream 'error' callback called with 'Error: Invocation canceled due to the underlying connection being closed.' threw error: Error: from error/);
1243+
});
11931244
});
11941245

11951246
describe("onClose", () => {

0 commit comments

Comments
 (0)