-
-
Notifications
You must be signed in to change notification settings - Fork 9.3k
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
Core: Fix startup hang caused by watchStorySpecifiers #27016
Conversation
Big savings 👍 🎉 |
Hey @heyimalex thanks a lot for your PR. So the @tmeasday could you please take a look at this PR? Thanks! |
@heyimalex thanks so much for putting this together. i just created a new PR that adds another Watchpack watcher. It's watching the config directory (e.g. |
@yannbf Sorry, I've updated the title. Yes, this is still an issue, it's been around for as long as @shilman I believe the same issue will exist, but it's IMO less likely to be problematic because |
This seems great @heyimalex. Some questions:
I'm not really understanding why given we pass in the same set of directories it doesn't actually end up needing to recurse anyway, but it seems like you have a good handle on this :)
I suppose there is no real way we can guarantee this, is there? But it is good that the perf boost is there in the case that it does happen. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code changes LGTM
// Takes an array of absolute paths to directories and synchronously returns | ||
// absolute paths to all existing files and directories nested within those | ||
// directories (including the passed parent directories). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this need to be sync? If we do it async might it give other parts of our boot up a chance to do work while waiting on FS?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it must be sync, we'd just create the watcher asynchronously after directory walking completes. IMO performance implications here are not significant tho, even with 10k directories readdirSync calls seem to complete in negligible time.
Forgive me if this isn't perfectly accurate, haven't really worked on this in a couple of years. So watchpack has direct watchers and recursive watchers. It has a function called reducePlan which takes a mapping of paths to watch, and intelligently collapses them down, creating recursive watchers to replace multiple direct watchers, so that the total number of watchers is below the limit. When passing in all directories, this reduce plan runs once, and (given the repro conditions) watchpack will recognize that a single recursive watcher is the best move. When passing in a single top level directory, essentially what happens is every time a readdir call completes, watchpack calls watch on each of the returned directories, and reducePlan runs again. You can see a "trace" of this behavior (created with hacky console log instrumenting) here. It ultimately gets to the same plan (see the final
No, there isn't, this is more of a best-case-scenario optimization. Also, just want to call out another possible solution: using a different library. The actual thing we're using watchpack for seems pretty simple on its face: we need to watch directories and trigger a callback when files that match some pattern nested within those directories are added, removed, or updated. Watchpack was probably seen as an easy enough way to get there, and something we already had a transitive dependency on, but given the level of footgunnery here maybe a different dep is appropriate. |
Agree 💯 ! If you have another suggestion I'm all ears! |
☁️ Nx Cloud ReportCI is running/has finished running commands for commit 80f8dc0. As they complete they will appear below. Click to see the status, the terminal output, and the build insights. 📂 See all runs for this CI Pipeline Execution ✅ Successfully ran 1 targetSent with 💌 from NxCloud. |
After some light research, evaluating file watching libs is really hard hahaha. It seems like @parcel/watcher may be a good choice, as it's what's currently used by vscode. chokidar is widely deployed, but vscode moved away from it. Many other small libraries that seem to have spotty cross platform support or not be maintained. |
Alternative branch here, but this PR is definitely lower risk. |
Thanks @heyimalex. We are in feature freeze right now but I'll aim to get this or the other one merged soon after 8.1 goes out. |
@heyimalex thanks for your patience on this. we're releasing 8.1 in a day or two and i'm planning to merge this as soon as we get that out so it has some time to bake for 8.2. excellent work!!! 🙌 |
@shilman we should consider the other PR that migrates us to Parcel's file watcher. |
Greate call @tmeasday -- I totally missed that. Let's discuss at the next available opportunity! |
Closes #18881
What I did
Changed how watchpack gets initialized in
watchStorySpecifiers
. Previously we:Now we:
This fixes two issues:
WATCHPACK_WATCHER_LIMIT
threshold. The outcome was multi-second hangs on startup. See the repro in the linked issue, it's incredibly simple and reliably fails on OSX.Reproduce the original issue by checking out
next
and setting up a sandbox.cd
into the sandbox.Run
yarn storybook
and note the time to startup. On my machine, 334 ms for manager and 880 ms for preview.Open node and run this to create a bunch of empty subdirectories within the sandbox.
Now run
yarn storybook
again. On my machine, 44 s for manager and 703 ms for preview.Checkout this branch and run the test again. On my machine, 254 ms for manager and 669 ms for preview.
Checklist for Contributors
Testing
Updated some tests, didn't love how it went.
The changes in this PR are covered in the following automated tests:
Manual testing
Did
console.log
testing / manual testing on the shape of everything in a sandbox.Documentation
N/A
MIGRATION.MD
Checklist for Maintainers
When this PR is ready for testing, make sure to add
ci:normal
,ci:merged
orci:daily
GH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found incode/lib/cli/src/sandbox-templates.ts
Make sure this PR contains one of the labels below:
Available labels
bug
: Internal changes that fixes incorrect behavior.maintenance
: User-facing maintenance tasks.dependencies
: Upgrading (sometimes downgrading) dependencies.build
: Internal-facing build tooling & test updates. Will not show up in release changelog.cleanup
: Minor cleanup style change. Will not show up in release changelog.documentation
: Documentation only changes. Will not show up in release changelog.feature request
: Introducing a new feature.BREAKING CHANGE
: Changes that break compatibility in some way with current major version.other
: Changes that don't fit in the above categories.