Skip to content

[labs/ssr] fix: RenderResultReadable skipping async work#4389

Merged
AndrewJakubowicz merged 5 commits intomainfrom
bug-render-result-readable
Nov 11, 2023
Merged

[labs/ssr] fix: RenderResultReadable skipping async work#4389
AndrewJakubowicz merged 5 commits intomainfrom
bug-render-result-readable

Conversation

@AndrewJakubowicz
Copy link
Copy Markdown
Contributor

@AndrewJakubowicz AndrewJakubowicz commented Nov 10, 2023

Context

Fix a race condition bug with RenderResultReadable.

What is the bug?

The RenderResultReadable class lets us efficiently stream synchronous or async iterables. It's architecture is designed to be as optimal as possible, so synchronous streams go fast and have minimal overhead from the async handling.

Our RenderResultReadable.prototype._read implementation is async, allowing us to await values in the stream.
From Node.js documentation: "_read() will be called again after each call to this.push(dataChunk) once the stream is ready to accept more data."

This is also the behavior back to Node.js v10.

What happens for the test case below (without the fix) when we are reading from the stream:

new RenderResultReadable([
    'a',
    new Promise((res) => setTimeout(res, 50)).then((_) => ['b']),
    'c',
]);
  1. Node.js calls _read(). We synchronously push('a').
  2. Our _read encounters the promise and awaits the promise.
  3. Node.js calls _read(), and we synchronously push('c'), then we loop and synchronously call push(null) terminating the stream.

Thus the promise is skipped.

Fix

Once _read() is called, it will not be called again until readable.push() has been called. This makes it safe for us to noop a _read() call while a Promise is waiting. Then once that promise resolves, it will result in push() being called with the resolved data and we're back in a consistent state.

Test plan

I added two tests that reproduce without the _waiting flag.

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Nov 10, 2023

🦋 Changeset detected

Latest commit: f69076e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@lit-labs/ssr Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Nov 10, 2023

📊 Tachometer Benchmark Results

Summary

nop-update

  • this-change, tip-of-tree, previous-release: unsure 🔍 -4% - +6% (-0.41ms - +0.70ms)
    this-change vs tip-of-tree

render

  • this-change: 49.04ms - 51.64ms
  • this-change, tip-of-tree, previous-release: unsure 🔍 -4% - +3% (-0.72ms - +0.66ms)
    this-change vs tip-of-tree
  • this-change, tip-of-tree, previous-release: unsure 🔍 -4% - +1% (-1.59ms - +0.35ms)
    this-change vs tip-of-tree
  • this-change, tip-of-tree, previous-release: unsure 🔍 -2% - +2% (-0.65ms - +0.68ms)
    this-change vs tip-of-tree

update

  • this-change: 560.57ms - 570.41ms
  • this-change, tip-of-tree, previous-release: unsure 🔍 -6% - +6% (-2.67ms - +2.51ms)
    this-change vs tip-of-tree
  • this-change, tip-of-tree, previous-release: unsure 🔍 -1% - +3% (-0.59ms - +2.10ms)
    this-change vs tip-of-tree
  • this-change, tip-of-tree, previous-release: unsure 🔍 -1% - +2% (-3.15ms - +8.91ms)
    this-change vs tip-of-tree

update-reflect

  • this-change: 552.48ms - 558.26ms
  • this-change, tip-of-tree, previous-release: unsure 🔍 -1% - +1% (-7.11ms - +6.75ms)
    this-change vs tip-of-tree

Results

this-change

render

VersionAvg timevs
49.04ms - 51.64ms-

update

VersionAvg timevs
560.57ms - 570.41ms-

update-reflect

VersionAvg timevs
552.48ms - 558.26ms-
this-change, tip-of-tree, previous-release

render

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
18.50ms - 19.58ms-unsure 🔍
-4% - +3%
-0.72ms - +0.66ms
unsure 🔍
-1% - +6%
-0.20ms - +1.14ms
tip-of-tree
tip-of-tree
18.64ms - 19.49msunsure 🔍
-3% - +4%
-0.66ms - +0.72ms
-unsure 🔍
-0% - +6%
-0.08ms - +1.07ms
previous-release
previous-release
18.19ms - 18.95msunsure 🔍
-6% - +1%
-1.14ms - +0.20ms
unsure 🔍
-6% - +0%
-1.07ms - +0.08ms
-

update

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
39.38ms - 42.84ms-unsure 🔍
-6% - +6%
-2.67ms - +2.51ms
unsure 🔍
-8% - +4%
-3.32ms - +1.74ms
tip-of-tree
tip-of-tree
39.26ms - 43.12msunsure 🔍
-6% - +6%
-2.51ms - +2.67ms
-unsure 🔍
-8% - +5%
-3.39ms - +1.96ms
previous-release
previous-release
40.05ms - 43.75msunsure 🔍
-4% - +8%
-1.74ms - +3.32ms
unsure 🔍
-5% - +8%
-1.96ms - +3.39ms
-

nop-update

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
11.25ms - 12.00ms-unsure 🔍
-4% - +6%
-0.41ms - +0.70ms
unsure 🔍
-2% - +7%
-0.26ms - +0.84ms
tip-of-tree
tip-of-tree
11.07ms - 11.89msunsure 🔍
-6% - +4%
-0.70ms - +0.41ms
-unsure 🔍
-4% - +6%
-0.42ms - +0.72ms
previous-release
previous-release
10.94ms - 11.73msunsure 🔍
-7% - +2%
-0.84ms - +0.26ms
unsure 🔍
-6% - +4%
-0.72ms - +0.42ms
-
this-change, tip-of-tree, previous-release

render

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
34.05ms - 35.02ms-unsure 🔍
-4% - +1%
-1.59ms - +0.35ms
unsure 🔍
-3% - +1%
-1.11ms - +0.45ms
tip-of-tree
tip-of-tree
34.31ms - 36.00msunsure 🔍
-1% - +5%
-0.35ms - +1.59ms
-unsure 🔍
-2% - +4%
-0.75ms - +1.33ms
previous-release
previous-release
34.25ms - 35.48msunsure 🔍
-1% - +3%
-0.45ms - +1.11ms
unsure 🔍
-4% - +2%
-1.33ms - +0.75ms
-

update

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
71.23ms - 73.54ms-unsure 🔍
-1% - +3%
-0.59ms - +2.10ms
unsure 🔍
-2% - +2%
-1.49ms - +1.73ms
tip-of-tree
tip-of-tree
70.94ms - 72.32msunsure 🔍
-3% - +1%
-2.10ms - +0.59ms
-unsure 🔍
-3% - +1%
-1.95ms - +0.68ms
previous-release
previous-release
71.14ms - 73.39msunsure 🔍
-2% - +2%
-1.73ms - +1.49ms
unsure 🔍
-1% - +3%
-0.68ms - +1.95ms
-
this-change, tip-of-tree, previous-release

render

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
34.07ms - 34.83ms-unsure 🔍
-2% - +2%
-0.65ms - +0.68ms
unsure 🔍
-2% - +2%
-0.58ms - +0.63ms
tip-of-tree
tip-of-tree
33.89ms - 34.98msunsure 🔍
-2% - +2%
-0.68ms - +0.65ms
-unsure 🔍
-2% - +2%
-0.71ms - +0.73ms
previous-release
previous-release
33.95ms - 34.90msunsure 🔍
-2% - +2%
-0.63ms - +0.58ms
unsure 🔍
-2% - +2%
-0.73ms - +0.71ms
-

update

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
568.84ms - 577.19ms-unsure 🔍
-1% - +2%
-3.15ms - +8.91ms
unsure 🔍
-1% - +1%
-7.01ms - +4.68ms
tip-of-tree
tip-of-tree
565.79ms - 574.49msunsure 🔍
-2% - +1%
-8.91ms - +3.15ms
-unsure 🔍
-2% - +0%
-10.02ms - +1.93ms
previous-release
previous-release
570.09ms - 578.27msunsure 🔍
-1% - +1%
-4.68ms - +7.01ms
unsure 🔍
-0% - +2%
-1.93ms - +10.02ms
-

update-reflect

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
567.30ms - 575.46ms-unsure 🔍
-1% - +1%
-7.11ms - +6.75ms
unsure 🔍
-1% - +1%
-4.79ms - +6.11ms
tip-of-tree
tip-of-tree
565.96ms - 577.16msunsure 🔍
-1% - +1%
-6.75ms - +7.11ms
-unsure 🔍
-1% - +1%
-5.83ms - +7.50ms
previous-release
previous-release
567.11ms - 574.33msunsure 🔍
-1% - +1%
-6.11ms - +4.79ms
unsure 🔍
-1% - +1%
-7.50ms - +5.83ms
-

tachometer-reporter-action v2 for Benchmarks

@github-actions
Copy link
Copy Markdown
Contributor

The size of lit-html.js and lit-core.min.js are as expected.

Copy link
Copy Markdown
Member

@augustjk augustjk left a comment

Choose a reason for hiding this comment

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

Nice find and fix!

@AndrewJakubowicz AndrewJakubowicz merged commit ef2976b into main Nov 11, 2023
@AndrewJakubowicz AndrewJakubowicz deleted the bug-render-result-readable branch November 11, 2023 00:39
This was referenced Nov 14, 2023
PonomareVlad added a commit to PonomareVlad/lit that referenced this pull request Nov 26, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants