-
Notifications
You must be signed in to change notification settings - Fork 10.4k
Refactor streaming from client to server #4559
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
src/SignalR/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnection.cs
Outdated
Show resolved
Hide resolved
src/SignalR/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnection.cs
Outdated
Show resolved
Hide resolved
src/SignalR/src/Microsoft.AspNetCore.SignalR.Common/Protocol/HubMethodInvocationMessage.cs
Outdated
Show resolved
Hide resolved
src/SignalR/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnection.cs
Outdated
Show resolved
Hide resolved
if (descriptor.OriginalParameterTypes[parameterPointer] == typeof(CancellationToken)) | ||
{ | ||
cts = CancellationTokenSource.CreateLinkedTokenSource(connection.ConnectionAborted); | ||
arguments[parameterPointer] = cts.Token; | ||
} | ||
else if (ReflectionHelper.IsStreamingType(descriptor.OriginalParameterTypes[parameterPointer], mustBeDirectType: true)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reflection here and line 242 is happening for every stream item right? Should cache it on the descriptor to pay the price once.
I think we should also support accepting a channel writer for sever to client streaming. This is something we discussed briefly but didn’t go into details on. It’s worth looking at as it could simplify the programming model. |
CloseMessage | | ||
StreamCompleteMessage | | ||
StreamDataMessage; | ||
CloseMessage; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should InvocationMessage and StreamInvocationMessage also be combined?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, those are how we distinguish between regular invocation and invocation that returns a stream to the client.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couldn't that be determined based on the signature of the hub method being invoked? Or the presence of the stream/streamIds property in the InvocationMessage?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Current design of the streamIds property is that it is only for streams from client to server.
And we can't rely on the signature of the Hub method to determine if the client intended to wait for a normal invocation response (via CompletionMessage) or a streamed response (via StreaItems + CompletionMessage). So we use two different invocation messages, StreamInvocationMessage and InvocationMessage
src/SignalR/src/Microsoft.AspNetCore.SignalR.Common/Protocol/HubMethodInvocationMessage.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still reviewing. I think some of my comments are already out of date with the commit you just made seconds ago
@@ -155,16 +141,6 @@ export interface CancelInvocationMessage extends HubInvocationMessage { | |||
readonly invocationId: string; | |||
} | |||
|
|||
/** A hub message sent to indicate the end of stream items for a streaming parameter. */ | |||
export interface StreamCompleteMessage extends HubMessageBase { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@@ -97,18 +95,6 @@ export interface StreamItemMessage extends HubInvocationMessage { | |||
readonly item?: any; | |||
} | |||
|
|||
/** A hub message representing a single stream item, transferred through a streaming parameter. */ | |||
export interface StreamDataMessage extends HubMessageBase { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
src/SignalR/src/Microsoft.AspNetCore.SignalR.Common/Protocol/HubMethodInvocationMessage.cs
Outdated
Show resolved
Hide resolved
.../Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson/Protocol/NewtonsoftJsonHubProtocol.cs
Outdated
Show resolved
Hide resolved
@@ -112,7 +112,7 @@ public override string ToString() | |||
|
|||
try | |||
{ | |||
streamIds = string.Join(", ", StreamIds?.Select(id => id?.ToString())); | |||
streamIds = string.Join(", ", StreamIds != null ? StreamIds.Select(id => id?.ToString()) : Array.Empty<string>()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should an error be thrown for a null streamId?
This place might not be the right place but null stream ids off the wire are something that should be guarded against.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we should care if stream ids is null, it's similar to how we don't care about extra data in the protocol
src/SignalR/src/Microsoft.AspNetCore.SignalR.Core/Internal/DefaultHubDispatcher.cs
Outdated
Show resolved
Hide resolved
src/SignalR/clients/ts/signalr-protocol-msgpack/src/MessagePackHubProtocol.ts
Outdated
Show resolved
Hide resolved
...lR/src/Microsoft.AspNetCore.SignalR.Protocols.MessagePack/Protocol/MessagePackHubProtocol.cs
Outdated
Show resolved
Hide resolved
...lR/src/Microsoft.AspNetCore.SignalR.Protocols.MessagePack/Protocol/MessagePackHubProtocol.cs
Outdated
Show resolved
Hide resolved
.../Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson/Protocol/NewtonsoftJsonHubProtocol.cs
Outdated
Show resolved
Hide resolved
.../Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson/Protocol/NewtonsoftJsonHubProtocol.cs
Outdated
Show resolved
Hide resolved
.../Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson/Protocol/NewtonsoftJsonHubProtocol.cs
Outdated
Show resolved
Hide resolved
src/SignalR/test/Microsoft.AspNetCore.SignalR.Tests.Utils/TestClient.cs
Outdated
Show resolved
Hide resolved
src/SignalR/test/Microsoft.AspNetCore.SignalR.Tests.Utils/TestClient.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
...icrosoft.AspNetCore.SignalR.Common.Tests/Internal/Protocol/TestHubMessageEqualityComparer.cs
Show resolved
Hide resolved
ee0f461
to
93df7af
Compare
Ping, anymore code comments while I finish up the spec? |
af6dc8f
to
1d350ab
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some comments on the spec. Let's get this in
Should we put the streaming from client feature behind a check for the |
I think the error should occur when a newer client attempts to connect to an older server instead of waiting for the client to attempt stream. AFAIK, SignalR clients have never selectively supported features based on server protocol version. It's always been all or nothing. That way you don't have to worry about providing a feature detection API. If you want to start using a new feature, you have to upgrade all your servers. In the past, we considered requiring server upgrades a smaller ask than requiring client upgrades anyway. |
Started doing some microbenchmarking with the changes:
This shows that there is greater up-front costs for client->server streaming
And lower per-item cost when comparing sending 1000 of the same messages in streaming vs invoking. |
339716d
to
9b62ba4
Compare
...alR/benchmarks/Microsoft.AspNetCore.SignalR.Microbenchmarks/DefaultHubDispatcherBenchmark.cs
Outdated
Show resolved
Hide resolved
9b62ba4
to
bc3af25
Compare
Fixes https://github.com/aspnet/SignalR/issues/2592
Fixes #4401
TODO: