Skip to content
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

[SignalR] Stateful reconnect #46691

Closed
4 of 15 tasks
BrennanConroy opened this issue Feb 15, 2023 · 35 comments
Closed
4 of 15 tasks

[SignalR] Stateful reconnect #46691

BrennanConroy opened this issue Feb 15, 2023 · 35 comments
Assignees
Labels
area-signalr Includes: SignalR clients and servers

Comments

@BrennanConroy
Copy link
Member

BrennanConroy commented Feb 15, 2023

Allows the server to retain the send buffer while the client is reconnecting and preserve connection state (Context.Items, connection ID, etc.).

Thoughts:

  • Would need to be opt-in and supported by both client and server. Because client needs to change to try to reconnect with the same connection ID as its previous connection.
  • Need an option to configure how long to keep the connection state on the server
  • Skip negotiate doesn't play well in a multi-server environment when sticky-sessions aren't enabled
  • How does it work with Azure SignalR Service
  • Does the client need a new event to say "doing stateful reconnect"? What's the interaction with the current automatic reconnect feature?
  • If client connects with different auth credentials, do we replace the User?

Needs work:

  • Configurable buffer limit(s), total bytes count and maybe total message count too
  • Versioning, probably increment HubProtocol and add "ack protocol"
  • Try to push feature fully into SignalR layer, i.e. get new ConnectionContext from lower layer and map onto existing connection
    • Replace IReconnectFeature with IExistingConnectionFeature or something, that contains the previous ID on the new ConnectionContext (because client will send old id via query string)
    • Need timeout logic in SignalR layer then
    • And pause the read loop waiting for a new connection
    • Figure out what happens when a seamless reconnect takes too long, do we just kill the connection attempt, or keep it as a new connection (since the ConnectionContext is completely new) and send the new ID back to the client somehow?
    • Potentially send a CloseMessage from clients to have a guaranteed way of knowing the connection close is graceful
  • If not, finalize IReconnectFeature API
  • Fix StopAsync race in WebSocketsTransport (Running task being overwritten), it might be delaying reconnect fallback logic
  • Pool buffers in MessageBuffer
  • Finalize options for enabling the feature, both client and server side
    • And disallowing the feature from server side
  • Retry policy for seamless reconnect attempts, separate from current reconnect policies
  • Fix many TODOs in current code
@johnkattenhorn
Copy link

Hey @BrennanConroy, we've seen the pull request and the proposal, we think this will be a great feature for our use-case of mobile gaming which we've been working with @kevinguo305 on. We are working on a plan to put a reference architecture to illustrate how to use signalR in gaming.

@kevinguo305 - do you know if the team who built the UnityClient are aware of this work going on this feature ?

@BrennanConroy
Copy link
Member Author

Glad to hear it! Are you in a position to be able to try out .NET previews? We're planning on getting the initial implementation into 8.0-preview5 and would love to find folks to try it out and make sure it works well.

@johnkattenhorn
Copy link

Yep - we would be happy to try it out.

@BrennanConroy
Copy link
Member Author

@johnkattenhorn preview 5 is out.
To try this out you have to use the .NET client with WebSockets and enable the feature option:

var hubConnection = new HubConnectionBuilder()
    .WithUrl("<hub url>",
             options =>
             {
                options.UseAcks = true;
             })
    .Build();

@TimChen44
Copy link

This capability is too important for Blazor Server, and I hope that in the future, Blazor Server will not cause the entire program to crash due to network reasons.

@Webreaper
Copy link

Glad to hear it! Are you in a position to be able to try out .NET previews?

I'd love to try/test this, but for some reason .Net 8 previews still aren't supported by VS for Mac. Maybe in preview 6?

@m33p
Copy link

m33p commented Jun 24, 2023

I wanted to give my feedback and this feature.
This feature is amazing and a must have. I've been engaging with our VPN team with connection issues to our Blazor application. One of our VPN or firewall is dropping the websocket connection. After testing with this feature turned on the issue isn't even noticeable. Please ship this with .NET 8.

@adityamandaleeka
Copy link
Member

That's great to hear @m33p. @johnkattenhorn Have you had a chance to try it as well?

As you've seen, we got the initial implementation out in preview 5 and plan to make some improvements in preview 7. I'm moving the milestone on this issue to reflect that.

@johnkattenhorn
Copy link

Hey @adityamandaleeka,

I've asked the team if we have any feedback in this and will come back asap.

@agrubbszenzio
Copy link

@johnkattenhorn preview 5 is out. To try this out you have to use the .NET client with WebSockets and enable the feature option:

var hubConnection = new HubConnectionBuilder()
    .WithUrl("<hub url>",
             options =>
             {
                options.UseAcks = true;
             })
    .Build();

Looking for documentation on where to implement this. Can this be placed in the program.cs?

We have a dashboard business app that loses connectivity and are planning to give this a go. We are hoping to keep the project in Blazor server side.

Thanks

@BrennanConroy
Copy link
Member Author

connection issues to our Blazor application.

@m33p I assume you're using Blazor WASM and have a component using HubConnection? Glad that it's working better for you!

We are hoping to keep the project in Blazor server side.

@agrubbszenzio This isn't possible yet since Blazor server side uses the Javascript SignalR client which doesn't implement this feature yet. We're nailing down the details with the .NET client first before getting other clients updated. Javascript client will be next though.

8.0-preview6 is out today and does require the server to opt-in to this feature now to use it.

Example code:
Server:

app.MapHub<AppHub>("/default", o => o.AllowAcks = true);

Client:

var hubConnection = new HubConnectionBuilder()
    .WithUrl("<hub url>",
             options =>
             {
                options.UseAcks = true;
             })
    .Build();

@Webreaper
Copy link

8.0-preview6 is out today and does require the server to opt-in to this feature now to use it.

This is exciting - I'd like to try it. Do we know if preview 6 will finally add VS for Mac support?

@BrennanConroy
Copy link
Member Author

Do we know if preview 6 will finally add VS for Mac support?

No idea. I think the relationship is the other way around though: "Does VS for Mac support 8.0-preview6?"

@Webreaper
Copy link

Turns out the answer is Yes!

@Webreaper
Copy link

I'm trying this in my app, but I'm getting an error for options.UseAcks = true; - compiler is saying there's no UseAcks property. This is with .Net 8 preview 6. Did it definitely get into the release?

@BrennanConroy
Copy link
Member Author

I'm trying this in my app, but I'm getting an error for options.UseAcks = true; - compiler is saying there's no UseAcks property. This is with .Net 8 preview 6. Did it definitely get into the release?

Yes, it's definitely been present since preview5. This likely means you aren't actually using the preview builds.

@Webreaper
Copy link

Yes, it's definitely been present since preview5. This likely means you aren't actually using the preview builds.

I was definitely using the preview builds, because I had other code using features from preview 6. However, I just uncommented that line, and it's not generating a compiler error (I haven't installed any updated SDKs since I last tried). Very very weird. But looks better now!

@adityamandaleeka adityamandaleeka removed this from the 8.0-preview7 milestone Jul 28, 2023
@adityamandaleeka adityamandaleeka added this to the 8.0-rc1 milestone Jul 28, 2023
@WhitWaldo
Copy link

This isn't possible yet since Blazor server side uses the Javascript SignalR client which doesn't implement this feature yet. We're nailing down the details with the .NET client first before getting other clients updated. Javascript client will be next though.

I, too, am really looking forward to seeing this functionality in Blazor Server once it's been fleshed out in this context.

@juanyacovino77
Copy link

Hey,

is there a guaranteed way of sharing state between SignalR client and the hub? I mean guaranteed because we know HttpContext it is not.

For example, I would like to receive data from the client at the OnConnected() Hub event... How could I make this? (out of using headers and cookies)

Let say I have the list of connectionId s mapped with user id at in-memory dictionary or using Context.Items.. at the moment the conection get disconnected I need to map that (disconnected) connectionid to the corresponding connected new one ...(in order to identify the same device) The only way of mapping the last disconnect connectionId with the new one it to define a new hub method and call it from the client with the parameters.

I am using ASP.NET Core 6.

it would be useful to have more info about the SignalR conection context (not http)

thanks

@benguenter
Copy link

Very excited about this feature, at what point after the .net 8 release will this be available when using the Azure SignalR Service?

@Sebazzz
Copy link

Sebazzz commented Sep 12, 2023

This isn't possible yet since Blazor server side uses the Javascript SignalR client which doesn't implement this feature yet.

Is this expected before RTM, or do we need to wait on .NET 9 for that?

@BrennanConroy
Copy link
Member Author

This isn't possible yet since Blazor server side uses the Javascript SignalR client which doesn't implement this feature yet.

Is this expected before RTM, or do we need to wait on .NET 9 for that?

This will work in 8.0-rc2

@adityamandaleeka
Copy link
Member

@BrennanConroy can we call this issue done now?

@pigwing
Copy link

pigwing commented Oct 11, 2023

This isn't possible yet since Blazor server side uses the Javascript SignalR client which doesn't implement this feature yet.

Is this expected before RTM, or do we need to wait on .NET 9 for that?

This will work in 8.0-rc2

https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-dotnet-8-rc-2/
image

blazor haven't updated it yet?^_^

@BrennanConroy
Copy link
Member Author

Blazor can be configured for the client side via https://learn.microsoft.com/aspnet/core/blazor/fundamentals/signalr?view=aspnetcore-7.0#configure-signalr-timeouts-and-keep-alive-on-the-client, you still need server side settings as well.

@pigwing
Copy link

pigwing commented Oct 11, 2023

thx

@kescherCode
Copy link

Would this work with Azure SignalR as-is or will it require explicit support on their end?

@BrennanConroy
Copy link
Member Author

Azure SignalR Service requires explicit support.

@hrytskivr
Copy link

hrytskivr commented Oct 12, 2023

Can this work with Redis backplane and when web-api is scaled out behind load balancer?
With sticky sessions not configured and skipNegotiation: true on the client side.

@BrennanConroy
Copy link
Member Author

With sticky sessions not configured and skipNegotiation: true on the client side.

No, you need sticky sessions.

@XorZy
Copy link

XorZy commented Oct 13, 2023

How to configure the server to enable stateful reconnect with InteractiveServerRenderMode?
I don't see where in the new template one could set that option.

@pigwing
Copy link

pigwing commented Oct 16, 2023

app.MapRazorComponents<App>() .AddInteractiveServerRenderMode().Add(convention => { var meta = convention.Metadata.FirstOrDefault(e => e is HttpConnectionDispatcherOptions); if (meta != null) { HttpConnectionDispatcherOptions options = (HttpConnectionDispatcherOptions)meta; options.AllowStatefulReconnects = true; } });
I found this method at present.

@mkArtakMSFT
Copy link
Member

Removing the milestone for the team to retriage

@Benedicht
Copy link

Is there an up-to-date documentation for implementors about this feature?

  • Main branch's TransportProtocols spec looks very out of date.
  • This version has some detail about the framing too, but i don't know how trustworthy the information.

@adityamandaleeka
Copy link
Member

@Benedicht I've opened #53103 to track your question about the doc. I'm going to close this issue now since it was originally meant to track getting stateful reconnect done, which has now shipped in .NET 8. Further work/issues can be tracked separately.

@ghost ghost locked as resolved and limited conversation to collaborators Feb 7, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-signalr Includes: SignalR clients and servers
Projects
None yet
Development

No branches or pull requests