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

[Blazor] Auto render mode improvements #53159

Merged
merged 7 commits into from Jan 10, 2024
Merged

Conversation

MackinnonBuck
Copy link
Member

@MackinnonBuck MackinnonBuck commented Jan 4, 2024

Auto render mode improvements

Improves the Auto render mode so that components are more responsive and have a decreased initial time to interactivity when WebAssembly resources are not already cached.

Description

This PR makes the following improvements:

  • Removes the timeout for loading the boot config. This prevents Server interactivity from always being used when the connection quality is poor.
  • Introduces a limit to the maximum parallel WebAssembly resource downloads when an Auto component initiates the startup of the WebAssembly runtime. This limit is set to 1 and overrides any user-specified limit.
  • Fixes an issue where the circuit sometimes remains open even if WebAssembly gets selected for Auto interactivity.

Another potential improvement is to defer the start of WebAssembly resource downloading until after the circuit starts. However, we may want to consider this as an enhancement for .NET 9 rather than include it in a .NET 8 servicing release because it's a larger and riskier change.

I've been testing these improvements on a published site hosted on Azure to collect real-world measurements and verify that these changes improve things in the way we expect. I also provided a preview of these changes in #52154 (comment) so that customers could try them out, and the feedback so far has been very positive.

Remaining work:

  • E2E tests
  • Continued real-world testing and validation on mobile scenarios

Fixes #52154

@ghost ghost added the area-blazor Includes: Blazor, Razor Components label Jan 4, 2024
@MackinnonBuck MackinnonBuck marked this pull request as ready for review January 9, 2024 22:16
@MackinnonBuck MackinnonBuck requested a review from a team as a code owner January 9, 2024 22:16
// If the WebAssembly runtime starts downloading because an Auto component was added to
// the page, we limit the maximum number of parallel WebAssembly resource downloads to 1
// so that the performance of any Blazor Server circuit is minimally impacted.
this.startLoadingWebAssemblyIfNotStarted(/* maxParallelDownloadsOverride */ 1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean if there's a combination of WebAssembly and Auto components on the page, the maxParallelDownloadsOverride value will end up being determined by which of them appeared first in the DOM?

If so that's slightly quirky but most likely not a problem in real life, as people will almost never mix both of those modes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with Steve here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might be able to partially mitigate this by changing this method to accept the full set of discovered ComponentDescriptors all at once. Then if any descriptors have type 'webassembly', download WebAssembly resources with full (or user-specified) parallelism. Otherwise, if there are any 'auto' descriptors, download WebAssembly resources with no parallelism. But considering that mixing 'auto' and 'webassembly' is an uncommon use case, and that it's preferable to keep servicing changes minimal, I would propose that we make any further adjustments in .NET 9.

Long-term, it might be preferable to be able to dynamically change the throttling amount so that if a WebAssembly component appears on the page after an Auto component already initiated the downloading of WebAssembly resources, we would switch to downloading with full parallelism, so the WebAssembly component becomes interactive as quickly as possible.

I'll open an issue to track this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

@SteveSandersonMS SteveSandersonMS left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great.

I thought before you mentioned we'd need a runtime change in order to be able to override the parallelism. Has that change been made now? Or did you find another way to do it?

@MackinnonBuck
Copy link
Member Author

MackinnonBuck commented Jan 10, 2024

I thought before you mentioned we'd need a runtime change in order to be able to override the parallelism. Has that change been made now? Or did you find another way to do it?

The merged runtime fix enabling this can be found here

@MackinnonBuck MackinnonBuck merged commit d5a8d01 into main Jan 10, 2024
26 checks passed
@MackinnonBuck MackinnonBuck deleted the mbuck/auto-improvements branch January 10, 2024 22:52
@ghost ghost added this to the 9.0-preview1 milestone Jan 10, 2024
@ihorlazarenko
Copy link

I have tested auto render mode after fix and found it still useless in a few network's latency modes. When network connection is super fast(localhost for example) assemblies are loaded before any web socket connection starts. When connection is slow, loading of assemblies is slow and server rendering lags and both interrupt each other which influences in even worse UX(server rendering is laggier until web assembly cache is downloaded and web assembly load time is bigger). From my point of view strategy should be next: if dlls is not cache then use server rendering without interruption with loading of DLLs, load dlls only when server rendering does not perform any network requests.

@SteveSandersonMS
Copy link
Member

@ihorlazarenko Thanks for looking into it.

When network connection is super fast(localhost for example) assemblies are loaded before any web socket connection starts.

To be honest that doesn't seem like a problem to me. Not sure what other behavior you'd want in that case.

When connection is slow, loading of assemblies is slow and server rendering lags and both interrupt each other which influences in even worse UX

That does seem problematic but I thought that was one of the issues we specifically fixed. How do you know that the WebAssembly file loading is interrupting the WebSocket connection, as opposed to lag simply being caused by the connection being slow? The updated logic already limits the WebAssembly file loading to a single connection, so there should always be at least one other outbound connection slot available for the WebSocket connection.

load dlls only when server rendering does not perform any network requests.

Server rendering is a WebSocket connection so it's hard to determine what is meant by "does not perform any network requests". There is always going to be a single network connection for the WebSocket connection, and it stays open for as long as you have an active circuit. The user can perform interactions at any moment, unpredictably, and when they do so we need to send and receive traffic ASAP to keep the UI responsive.

If there are specific ways you know of that the WebAssembly file loading can be deprioritized to minimize network impact please let us know. The fetch API does have a priority option. I'm not certain how it would interact in practice but it might be something for us to try next depending on what other feedback we get on the improved Auto mode. Much of the other feedback so far has been positive, so perhaps in a lot of cases things will already work well.

@ihorlazarenko
Copy link

let me describe more concrete example. I have created solution from template where server project + counter page in client project. Server project has static renderer with navigation and counter has auto renderer. I changed only rendering mode in counter page. First I disabled prerendering in counter and run in auto mode without prerendering in browser with "slow 3g" network option. After nearly 30-35 seconds page was rendered in interaction server mode(DLLs were loaded after 2 minutes) and while loading control was a little bit laggy(waiting for counter update after clicking). When I switched to pure server rendering without prerendering I got rendered page after 9-10 seconds without noticeable lags. So the difference between auto and server mode is 35 and 10 seconds for this connection. There is nearly the same proportion using another network speed. Why do not use only server rendering in auto mode until control was rendered at least first time?

@ghost
Copy link

ghost commented Jan 26, 2024

Hi @ihorlazarenko. It looks like you just commented on a closed PR. The team will most probably miss it. If you'd like to bring something important up to their attention, consider filing a new issue and add enough details to build context.

@mikes-gh
Copy link
Contributor

@MackinnonBuck I see this PR is labelled 9.0.preview1 Do we have to wait till November 24 for this much talked about net8.0 feature to work?

@ghost
Copy link

ghost commented Jan 31, 2024

Hi @mikes-gh. It looks like you just commented on a closed PR. The team will most probably miss it. If you'd like to bring something important up to their attention, consider filing a new issue and add enough details to build context.

@MackinnonBuck
Copy link
Member Author

@mikes-gh This is the PR targeting the main branch, but the same fix was taken in an internal PR and will be included in the upcoming 8.0.2 release.

@dotnet dotnet deleted a comment Jan 31, 2024
dotnet-bot pushed a commit that referenced this pull request Feb 13, 2024
# Auto render mode improvements

Backport of #53159

Improves the Auto render mode so that components are more responsive and have a decreased initial time to interactivity when WebAssembly resources are not already cached.

## Description

One of the goals of the Auto render mode was to allow apps to become interactive as quickly as possible via Server interactivity, while WebAssembly bits were downloaded in the background for use on future visits to the site. However, since WebAssembly resources were being downloaded with maximal parallelism, the quality of the websocket connection required for Server interactivity was negatively impacted, often to the extent that the websocket wouldn't connect until WebAssembly resources had finished downloading completely, largely defeating the purpose of the Auto render mode.

This PR makes the following improvements:
* Removes a problematic timeout on loading the WebAssembly boot config. This fixes a problem where Server interactivity was always being used when the boot config took too long to load.
* Introduces a limit to the maximum parallel WebAssembly resource downloads when an Auto component initiates the startup of the WebAssembly runtime. This limit is set to 1 and overrides any user-specified limit.
* Fixes an issue where the circuit sometimes remains open even if WebAssembly gets selected for Auto interactivity.

I provided a preview of these changes in #52154 (comment) so that customers could try them out, and the feedback so far has been very positive.

Fixes #52154

## Customer Impact

A significant number of customers reported being affected by this problem in issues like #52154. I supplied customers with a preview of the fix that they could patch it into their app, and many indicated that their problems were resolved by the fix. The Auto render mode was one of the key features released in .NET 8, so it's important that it works in the way we've been advertising.
 
## Regression?

- [ ] Yes
- [X] No

## Risk

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

The core Auto render mode functionality is unaffected by this change - we added small tweaks to adjust the throttling amount and remove a problematic timeout. Additional tests were added to verify the changes in behavior, and we've been testing these changes manually to ensure they work well in real-world scenarios (various device types and connection qualities).

## Verification

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

## Packaging changes reviewed?

- [ ] Yes
- [ ] No
- [X] N/A
3dots pushed a commit to 3dots/aspnetcore-Web.JS that referenced this pull request Feb 19, 2024
# Auto render mode improvements

Backport of dotnet/aspnetcore#53159

Improves the Auto render mode so that components are more responsive and have a decreased initial time to interactivity when WebAssembly resources are not already cached.

## Description

One of the goals of the Auto render mode was to allow apps to become interactive as quickly as possible via Server interactivity, while WebAssembly bits were downloaded in the background for use on future visits to the site. However, since WebAssembly resources were being downloaded with maximal parallelism, the quality of the websocket connection required for Server interactivity was negatively impacted, often to the extent that the websocket wouldn't connect until WebAssembly resources had finished downloading completely, largely defeating the purpose of the Auto render mode.

This PR makes the following improvements:
* Removes a problematic timeout on loading the WebAssembly boot config. This fixes a problem where Server interactivity was always being used when the boot config took too long to load.
* Introduces a limit to the maximum parallel WebAssembly resource downloads when an Auto component initiates the startup of the WebAssembly runtime. This limit is set to 1 and overrides any user-specified limit.
* Fixes an issue where the circuit sometimes remains open even if WebAssembly gets selected for Auto interactivity.

I provided a preview of these changes in dotnet/aspnetcore#52154 (comment) so that customers could try them out, and the feedback so far has been very positive.

Fixes dotnet/aspnetcore#52154

## Customer Impact

A significant number of customers reported being affected by this problem in issues like dotnet/aspnetcore#52154. I supplied customers with a preview of the fix that they could patch it into their app, and many indicated that their problems were resolved by the fix. The Auto render mode was one of the key features released in .NET 8, so it's important that it works in the way we've been advertising.
 
## Regression?

- [ ] Yes
- [X] No

## Risk

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

The core Auto render mode functionality is unaffected by this change - we added small tweaks to adjust the throttling amount and remove a problematic timeout. Additional tests were added to verify the changes in behavior, and we've been testing these changes manually to ensure they work well in real-world scenarios (various device types and connection qualities).

## Verification

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

## Packaging changes reviewed?

- [ ] Yes
- [ ] No
- [X] N/A
@ihorlazarenko
Copy link

it still doesn't work in 8.0.2

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
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Blazor] Auto Render not working properly in .NET 8 and page locks until WebAssembly start
5 participants