Apply backpressure to WebViewRenderer's unacknowledged render batch queue - #68739
Apply backpressure to WebViewRenderer's unacknowledged render batch queue#68739Kebechet wants to merge 1 commit into
Conversation
|
Thanks for your PR, @Kebechet. Someone from the team will get assigned to your PR shortly and we'll get it reviewed. |
There was a problem hiding this comment.
Pull request overview
This PR adds backpressure to Blazor WebView rendering so WebViewRenderer stops producing new render batches when too many are outstanding (unacknowledged), resuming once acknowledgements arrive. It also includes an unrelated addition of a new ComponentBase protected API (IsAfterInitialization) with corresponding test and API-surface updates.
Changes:
- Add a cap (
MaxBufferedUnacknowledgedRenderBatches) and gateProcessPendingRender()to prevent unbounded accumulation of unacknowledged render batches inWebViewRenderer. - Resume deferred rendering when a batch acknowledgement is received (
NotifyRenderCompletedtriggersProcessPendingRender). - Add tests/helpers for the WebView backpressure behavior, and separately add
ComponentBase.IsAfterInitialization+ tests + PublicAPI updates.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Components/WebView/WebView/src/Services/WebViewRenderer.cs | Adds backpressure by gating rendering when the unacknowledged-batch queue reaches a fixed cap, and resumes on acknowledgement. |
| src/Components/WebView/WebView/test/WebViewRendererTests.cs | New unit tests validating that render batches stop at the cap and resume (flushing deferred work) after an acknowledgement. |
| src/Components/WebView/WebView/test/Infrastructure/TestWebViewManager.cs | Adds a ReceiveRenderCompletedMessage helper to drive acknowledgement behavior in tests. |
| src/Components/Components/src/ComponentBase.cs | Adds a new protected lifecycle-state property IsAfterInitialization and renames the internal init-tracking field. |
| src/Components/Components/test/ComponentBaseTest.cs | Adds unit tests covering the new IsAfterInitialization behavior under sync init, async init, cancellation, and exceptions. |
| src/Components/Components/src/PublicAPI.Unshipped.txt | Records the new ComponentBase.IsAfterInitialization protected API surface addition. |
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
| /// <summary> | ||
| /// Indicates if the component finished calling the <see cref="OnInitialized"/> and <see cref="OnInitializedAsync"/>. | ||
| /// </summary> | ||
| protected bool IsAfterInitialization { get; private set; } |
There was a problem hiding this comment.
Good catch — those ComponentBase commits were unrelated local WIP that ended up under the branch by mistake. Removed by rebasing onto upstream/main; the PR now only contains the WebViewRenderer change and its tests.
| /// <summary> | ||
| /// Indicates if the component finished calling the <see cref="OnInitialized"/> and <see cref="OnInitializedAsync"/>. | ||
| /// </summary> | ||
| protected bool IsAfterInitialization { get; private set; } |
There was a problem hiding this comment.
This file was included by mistake and is no longer part of the PR (see the sibling thread).
…ueue Stop producing new render batches while the client has too many unacknowledged ones, mirroring RemoteRenderer.ProcessPendingRender and the default of CircuitOptions.MaxBufferedUnacknowledgedRenderBatches. Rendering resumes when a batch gets acknowledged.
5bce4a0 to
e560e26
Compare
Stop rendering while the WebView has too many unacknowledged render batches.
Description
WebViewRenderercurrently produces, serializes and dispatches render batches without bound even when the JS side has stopped acknowledging them — e.g. on Android, where the OS demotes and freezes the out-of-process WebView renderer while the backgrounded host app keeps rendering. In that state we measured 207 unacknowledged batches accumulating over a 39-minute background period, each retaining itsTaskCompletionSourceplus everything registered against it (updated-component id arrays, cloned disposed-event-handler ids,_eventBindingsentries) until acknowledged.This ports the backpressure
RemoteRendereralready applies for the equivalent scenario in Blazor Server:ProcessPendingRender()skips producing a new batch while the unacknowledged queue is at capacity. Pending renders stay coalesced in the base renderer's render queue, so retained state is bounded.NotifyRenderCompletedproduces any deferred renders once an acknowledgement frees a slot.The cap is an internal constant matching the default of
CircuitOptions.MaxBufferedUnacknowledgedRenderBatches(10), so there is no new public API. Happy to make it configurable (the WebView equivalent ofCircuitOptions) if that's preferred.Two unit tests cover the behavior via
TestWebViewManager: batches stop at the cap while acknowledgements are withheld (previously 21 batches were sent, unbounded), and the deferred renders flush as a single batch once one is acknowledged.TestWebViewManagergained aReceiveRenderCompletedMessagehelper mirroringReceiveAttachPageMessage.Notes:
RemoteRenderer'sFullUnacknowledgedRenderBatchesQueuewas left out to keep the diff minimal; I can add it if wanted.Fixes #68675