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

Better reconnection logic for Blazor Server #32113

Closed
konradbartecki opened this issue Apr 23, 2021 · 47 comments
Closed

Better reconnection logic for Blazor Server #32113

konradbartecki opened this issue Apr 23, 2021 · 47 comments
Assignees
Labels
area-blazor Includes: Blazor, Razor Components design-proposal This issue represents a design proposal for a different issue, linked in the description enhancement This issue represents an ask for new feature or an enhancement to an existing one Pillar: Complete Blazor Web Priority:1 Work that is critical for the release, but we could probably ship without
Milestone

Comments

@konradbartecki
Copy link

konradbartecki commented Apr 23, 2021

Summary

Currently there is an issue with Blazor Server-side where it is not reconnecting circuits automatically and losing connection especially on mobile browsers.

See #23340 #26985

Motivation and goals

In scope

image

Out of scope

Risks / unknowns

  • Difficult to test on mobile browsers

Examples

DefaultReconnectionHandler.ts

 async attemptPeriodicReconnection(options: ReconnectionOptions) {
    for (let i = 0; i < options.maxRetries; i++) {
      this.reconnectDisplay.update(i + 1);

      const delayDuration = i == 0 && options.retryIntervalMilliseconds > ReconnectionProcess.MaximumFirstRetryInterval
                            ? ReconnectionProcess.MaximumFirstRetryInterval
                            : options.retryIntervalMilliseconds;
      this.logger.log(LogLevel.Debug, `Reconnecting in ${delayDuration}`);
      await this.delay(delayDuration);
      //code..
      //try { reconnect() }
      
     //instead of delaying 3000ms first and trying to reconnect later
     //we could try to reconnect first and delay afterwards
     //this could possibly fix reconnection on suspended mobile browsers

Example onReconnectionFailed event default implementation

    Blazor.defaultReconnectionHandler.onReconnectionFailed = function (d) {
        document.location.reload(); 
    }

I can take care of the implementation of this task.

Related issues

#23340
#26985
#40721
#30344
#41791

@konradbartecki konradbartecki added the design-proposal This issue represents a design proposal for a different issue, linked in the description label Apr 23, 2021
@konradbartecki
Copy link
Author

konradbartecki commented Apr 23, 2021

I checked a debug release of my app and my assumptions were correct

On mobile the browser tab is getting awaken from the sleep
first we wait the default time of 3000ms
then we try to reconnect
then this attempt immediately fails because associated state is no longer available on the server (which makes sense)

Solution:

  • Reorganize code to try to reconnect first, delay afterwards
  • Reload the page after rejection as it is a better default.

WIP PR: #32122

@javiercn
Copy link
Member

@konradbartecki thanks for contacting us.

We have a feature in the works to better support this scenario in 6.0. You can check it here

We recommend you upvote that issue instead so that we can keep track of the interest as well as the issue covering general improvements for server-side Blazor here

@javiercn
Copy link
Member

javiercn commented Apr 26, 2021

I'm going to close this issue in favor of the two issues mentioned in my previous comment.

Nevermind, I see that there is a PR. We will evaluate it and see if we want to take it.

@javiercn javiercn added the ✔️ Resolution: Duplicate Resolved as a duplicate of another issue label Apr 26, 2021
@ghost ghost added the Status: Resolved label Apr 26, 2021
@javiercn javiercn reopened this Apr 26, 2021
@javiercn javiercn removed ✔️ Resolution: Duplicate Resolved as a duplicate of another issue Status: Resolved labels May 3, 2021
@mkArtakMSFT mkArtakMSFT added this to the Next sprint planning milestone May 3, 2021
@ghost
Copy link

ghost commented May 3, 2021

Thanks for contacting us.

We're moving this issue to the Next sprint planning milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s).
If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues.
To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

@ghost
Copy link

ghost commented Jul 27, 2021

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

@HybridSolutions
Copy link

Found some interesting results about this issue. Please check it here

@vindberg
Copy link

@konradbartecki is this something we can implement as a quick fix for our Server Blazor applications until the "real" solution is possible (now pushed to V8).

@konradbartecki
Copy link
Author

konradbartecki commented Aug 13, 2022

@vindberg Yes, I'm running let's say a custom fork, of dotnet/blazor with this fix only, so you could do it manually by:

  • Downloading dotnet/blazor source
  • Applying fixes locally
  • Building a dist version of blazor.server.js
  • Then in _Host.cshtml I just include my own blazor.server.js fork with this fix
    <script src="/blazor.server.js"></script>

See PR: #32122

@vindberg
Copy link

Thanks for getting back to me. I see there are some comments from @SteveSandersonMS about the delay and checks (two times ?). Have you included those?

I was hoping for an easier solution that didn't involve a custom fork of the repo. Im not sure MS knows how big an issue this is for Blazor adoption.

@mkArtakMSFT mkArtakMSFT added enhancement This issue represents an ask for new feature or an enhancement to an existing one and removed enhancement This issue represents an ask for new feature or an enhancement to an existing one labels Oct 11, 2022
@konradbartecki
Copy link
Author

Workaround: #30344 (comment)

@Ghevi
Copy link

Ghevi commented Feb 2, 2024

I'm trying this on a Blazor project with .Net 8 but the onConnectionDown function is never called.
This code works in .Net 7 where the first script src is _framework/blazor.server.js instead of _framework/blazor.web.js
Am i missing something?
Well it seems that using _framework/blazor.server.js works even in .Net 8 and everything seems fine, but i'm not using webassembly or auto rendering mode. The documentation says to use _framework/blazor.web.js in .Net 8...

<script src="_framework/blazor.web.js" autostart="false"></script>
<script>
        Blazor.start({
            reconnectionHandler: {
                onConnectionDown: () => {
                    console.log("connection down")
                },
                onConnectionUp: () => {
                    console.log("connection up")
                },
            },
        });
</script>

@TheXenocide
Copy link

It's possible this has been addressed in newer versions as I haven't focused much on reconnect logic recently, but one thing we ran into that presented challenges with reconnection was that the disposal of the scoped service provider was bound to the request lifetime, rather than the circuit lifetime, which results in ObjectDisposedExceptions when reconnecting to a state which has disposable injected services. Ideally, the circuit would keep the scoped service provider undisposed until the circuit is disposed.

@danroth27
Copy link
Member

One UX design issue to consider here (if it hasn't been already mentioned) is to have a reconnection UI that accounts for only part of the page being unresponsive. Currently we overlay the entire page, but it could be that only a single component on the page is using interactive server rendering.

@Johnhersh
Copy link

One UX design issue to consider here (if it hasn't been already mentioned) is to have a reconnection UI that accounts for only part of the page being unresponsive. Currently we overlay the entire page, but it could be that only a single component on the page is using interactive server rendering.

I would love to see that!

@rhires
Copy link

rhires commented Apr 3, 2024

It might be fun to start working this out as part of a debug session. It's sometimes painful when I'm trying to debug something and the browser loses the connection, which is surprising since it's a known connection and all that's happened is that I've hit a breakpoint but it takes "too long" for the connection to get refreshed, so it just hits that "1 of 8" thing. Like, how does it not know that I'm debugging? Can it figure out how it lost the connection? Or is that a stupid question? It would be useful for it "know" that I'm debugging so that it won't lose the connection.

@eschimmel
Copy link

@rhires The problem with debugging is indeed that it might cause a timeout. I partly solved this by adding log statements on the methods. When a method is entered, left and when an exception occurs. Adding these statements manually is tedious. I use the Metalama framework to have it done automatically. Not so long ago, I wrote a few articles about logging and the use of Aspect Oriented Programming and the Metalama framewrok. You can read the articles on my website at: https://byte217.com

@mkArtakMSFT mkArtakMSFT modified the milestones: 9.0-preview6, 9.0-preview5 May 1, 2024
mkArtakMSFT pushed a commit that referenced this issue May 28, 2024
# Updated Blazor Server reconnect UI

Improves the default Blazor Server reconnect experience according to common customer feedback.

## Description

Makes the following improvements to the Blazor Server reconnect UI:
* Rather than waiting three seconds before attempting reconnection, then waiting an additional default of 20 seconds between successive attempts, the new default settings use a configurable exponential backoff strategy:
  * Retry as quickly as possible for the first 10 attempts
  * Retry every 5 seconds for the next 10 attempts
  * Retry every 30 seconds until reaching the user-configured max retry count
  * **Note**: Customers can configure their own retry interval calculation function to override the default behavior
* When the user navigates back to the disconnected app from another app or browser tab, a reconnect attempt is immediately made
* If the server can be reached, but reconnection fails because server disposed the circuit, a refresh occurs automatically
* The default reconnect UI shows the number of seconds until the next reconnect attempt instead of the number of attempts remaining
* The styling of the default reconnect UI has been modernized

Fixes #55721

## Customer Impact

Customers of apps built using Blazor Server often complain about the reconnection experience, which has motivated Blazor developers to open issues like #32113 suggesting improvements to reduce the amount of time the customer spends looking at the reconnect UI. This PR addresses many of those common concerns by performing reconnection attempts more aggressively. Unless apps have overridden the default reconnection options, they will automatically get thew new reconnect behavior by upgrading to .NET 9. In addition, the default reconnect UI styling has been updated. Styling changes will not affect apps that have overridden the default reconnect UI.

## Regression?

- [ ] Yes
- [X] No

## Risk

- [ ] High
- [ ] Medium
- [X] Low

This change only affects the reconnection experience when using Blazor Server or Server interactivity in a Blazor Web App. We have existing automated tests verifying core reconnect functionality. It's possible that some customers may have been relying on the previous defaults, but they'll still be able to override the new defaults if desired.

## Verification

- [X] Manual (required)
- [X] Automated

## Packaging changes reviewed?

- [ ] Yes
- [ ] No
- [X] N/A
@mkArtakMSFT mkArtakMSFT modified the milestones: 9.0-preview6, 9.0-preview5 Jul 8, 2024
@mkArtakMSFT
Copy link
Member

This has been completed as part of #55721
Another set of improvements in this area is going to be handled separately as part of #56678 in the future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-blazor Includes: Blazor, Razor Components design-proposal This issue represents a design proposal for a different issue, linked in the description enhancement This issue represents an ask for new feature or an enhancement to an existing one Pillar: Complete Blazor Web Priority:1 Work that is critical for the release, but we could probably ship without
Projects
None yet
Development

Successfully merging a pull request may close this issue.