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

feat(turborepo): Process package change events asynchronously #8036

Merged
merged 6 commits into from Apr 25, 2024

Conversation

NicholasLYang
Copy link
Contributor

@NicholasLYang NicholasLYang commented Apr 24, 2024

Description

We were previously processing the package change events synchronously, which ended up creating too much lagging and therefore crashes. Now we spin up a thread that reads in the package change events, and accumulates the changed packages. A separate thread handles execution by taking those changed packages and spinning up a new run.

Also I changed our logic to just send rediscover events on lagging with the channel in the daemon server. No reason to crash the server in that case.

The first commit is more of a refactor to put the watch state into WatchClient, to clean up the state ahead of splitting into two threads. You can review commit by commit if you wish.

Testing Instructions

Tested on next.js, lagging is definitely improved.

Copy link

vercel bot commented Apr 24, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
examples-nonmonorepo ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 25, 2024 3:27pm
rust-docs ✅ Ready (Inspect) Visit Preview 💬 Add feedback Apr 25, 2024 3:27pm
8 Ignored Deployments
Name Status Preview Comments Updated (UTC)
examples-basic-web ⬜️ Ignored (Inspect) Visit Preview Apr 25, 2024 3:27pm
examples-designsystem-docs ⬜️ Ignored (Inspect) Visit Preview Apr 25, 2024 3:27pm
examples-gatsby-web ⬜️ Ignored (Inspect) Visit Preview Apr 25, 2024 3:27pm
examples-kitchensink-blog ⬜️ Ignored (Inspect) Visit Preview Apr 25, 2024 3:27pm
examples-native-web ⬜️ Ignored (Inspect) Visit Preview Apr 25, 2024 3:27pm
examples-svelte-web ⬜️ Ignored (Inspect) Visit Preview Apr 25, 2024 3:27pm
examples-tailwind-web ⬜️ Ignored (Inspect) Visit Preview Apr 25, 2024 3:27pm
examples-vite-web ⬜️ Ignored (Inspect) Visit Preview Apr 25, 2024 3:27pm

Copy link
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

Join @NicholasLYang and the rest of your teammates on Graphite Graphite

Copy link
Contributor

github-actions bot commented Apr 24, 2024

🟢 Turbopack Benchmark CI successful 🟢

Thanks

@NicholasLYang NicholasLYang marked this pull request as ready for review April 24, 2024 17:44
@NicholasLYang NicholasLYang requested a review from a team as a code owner April 24, 2024 17:44
@NicholasLYang NicholasLYang changed the title Refactoring in preparation for deduplicating events feat(turborepo): Process package change events asynchronously Apr 24, 2024
}

Err(Error::ConnectionClosed)
};

let run_fut = async {
loop {
if !changed_packages.lock().unwrap().borrow().is_empty() {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

There's a slight race condition here, but it's okay, since the amount of changed packages is always going to increase, not decrease (it's only decremented in this thread), so we'll always need to do a run. Also even if we don't run anything, it'll just be slightly inefficient.

Copy link
Contributor

github-actions bot commented Apr 24, 2024

🟢 CI successful 🟢

Thanks

Copy link
Contributor

@gsoltis gsoltis left a comment

Choose a reason for hiding this comment

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

The yield_now looks suspicious. But maybe it just needs a comment?

if !changed_packages.lock().unwrap().borrow().is_empty() {
self.execute_run(&changed_packages).await?;
}
yield_now().await;
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you document what's going on here? I'm guessing it's to avoid spinning and not receiving any new events...

Maybe there's a better way to structure that? Like a watch or something so we can block until there's a change?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah we could probably do this with a watch channel. Will give that a shot

Copy link
Contributor

Choose a reason for hiding this comment

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

I think with the watch, we don't need this line anymore, right?

let run_fut = async {
loop {
changed_pkgs_rx.changed().await?;
let changed_pkgs = changed_pkgs_rx.borrow_and_update();
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this will block the producing side until changed_pkgs is dropped. You may want to clone it so that the borrow is short-lived, or at least not held for the duration of a run.

Copy link
Contributor

Choose a reason for hiding this comment

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

Docs on borrowing here indicate that this is not recommended, and we should find a way to shorten the borrow.

if !changed_packages.lock().unwrap().borrow().is_empty() {
self.execute_run(&changed_packages).await?;
}
yield_now().await;
Copy link
Contributor

Choose a reason for hiding this comment

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

I think with the watch, we don't need this line anymore, right?

@NicholasLYang NicholasLYang merged commit 5e5f7d9 into main Apr 25, 2024
56 checks passed
@NicholasLYang NicholasLYang deleted the nicholasyang/dedupe-events branch April 25, 2024 17:04
NicholasLYang added a commit that referenced this pull request May 7, 2024
### Description

Like #8036, we need to split out the event processing loop from the
actual logic to avoid lagging channels. In this case we process the
changed files every 100ms.

Uses a `Trie` to store the paths since they'll likely have a lot of
overlap.

### Testing Instructions

<!--
  Give a quick description of steps to test your changes.
-->


Closes TURBO-2921
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants