-
Notifications
You must be signed in to change notification settings - Fork 23
fix(editor): deduplicate parallel getRoot calls in editor route #4851
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
base: app
Are you sure you want to change the base?
Conversation
Wrap getRoot() and getNavigationNode() methods with React.cache() to prevent N+1 API calls when multiple parallel slot components (@Sidebar, @versionSelect, @headertabs, @productSelect, @logo, @devpanel) independently fetch the same root resource. Each parallel slot was calling loader.getRoot(), creating separate promises that independently awaited getAuthState() and authConfig. While getRootCached was already cached, the outer async function was not, causing 7 simultaneous requests to /root?_rsc=*. Fixes FERN-DASHBOARD-EE, FERN-DASHBOARD-8R, FERN-DASHBOARD-8T, FERN-DASHBOARD-D1, FERN-DASHBOARD-93, FERN-DASHBOARD-E7, FERN-DASHBOARD-DY, FERN-DASHBOARD-BT, FERN-DASHBOARD-82 Co-Authored-By: [email protected] <[email protected]>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
sbawabe
left a comment
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.
this response is too large to be react cached so it throws errors -- this is why we use upstash/redis caching
Reverted React.cache() wrappers on getRoot/getNavigationNode in readonly-docs-loader.ts as the root response is too large (>2MB) for React's cache mechanism. Instead, implemented promise memoization at the loader instance level in getCachedEditableDocsLoader. This deduplicates parallel slot calls without hitting React.cache size limits: - Store in-flight promise for getRoot() on the loader instance - Store in-flight promises for getNavigationNode(id) in a Map keyed by id - All parallel slots share the same loader instance via getCachedEditableDocsLoader - Each navigation only makes one underlying API call instead of 7 This approach avoids the 2MB React.cache limit mentioned in readonly-docs-loader.ts:1117-1122 while still eliminating the N+1 API calls observed in Sentry. Co-Authored-By: [email protected] <[email protected]>
|
Thanks for catching this! You're absolutely right - the root response is too large for React.cache() (hits the 2MB limit mentioned in readonly-docs-loader.ts:1117-1122). I've updated the fix to use promise memoization instead:
The approach is simpler and more targeted - it only affects the dashboard editor route where the N+1 issue occurs, rather than changing the base docs-loader package. |
Fixes FERN-DASHBOARD-EE, FERN-DASHBOARD-8R, FERN-DASHBOARD-8T, FERN-DASHBOARD-D1, FERN-DASHBOARD-93, FERN-DASHBOARD-E7, FERN-DASHBOARD-DY, FERN-DASHBOARD-BT, FERN-DASHBOARD-82
Deduplicate parallel getRoot() calls in editor route
Wraps the
getRoot()andgetNavigationNode()methods in the DocsLoader withReact.cache()to prevent N+1 API calls when multiple parallel slot components independently fetch the same root resource.What was the motivation & context behind this PR?
The editor route uses Next.js parallel routes with 6+ slot components (@Sidebar, @versionSelect, @headertabs, @productSelect, @logo, @devpanel) that each independently call
loader.getRoot()during server-side rendering. While the underlyinggetRootCached()function was already cached, each parallel slot's call toloader.getRoot()created a new async function that independently awaitedgetAuthState()andauthConfig, resulting in 7 simultaneous HTTP requests to/root?_rsc=*as observed in Sentry.This caused the "N+1 API Call" error that has been occurring 9+ times recently according to Sentry logs.
How has this PR been tested?
/root?_rsc=*requestsgetRoot()andgetNavigationNode()were async functions without React.cache() wrappergetCachedEditableDocsLoader()Recommended testing:
/:orgName/editor/:docsUrl/:branch/:slug/rootrequest instead of 7Key review points:
getRoot()within the same React Server Component render pass (which the_rscquery parameters confirm)getCachedEditableDocsLoader(), so the cache is properly sharedLink to Devin run: https://app.devin.ai/sessions/e4430584100a4e0d951e387b9b245f42
Requested by: [email protected] (@dannysheridan)