Improve performance of contentScopesCount via a request-scoped DataLoader - #6113
Merged
Conversation
When querying the users list, the contentScopesCount field resolver ran once per row and recomputed the available content scopes each time. Route it through a request-scoped DataLoader that batches all users of a request, so the available content scopes are computed a single time per request. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RGR2hkqpqcXL4xk7rGqz7n
VPS-thodax
approved these changes
Aug 5, 2026
VPS-Obi
approved these changes
Aug 5, 2026
nsams
approved these changes
Aug 6, 2026
Member
|
much better than #5999 |
VPS-thodax
added a commit
that referenced
this pull request
Aug 13, 2026
…-scoped DataLoader (#6144) Backport of #6113 to `v8.x.x`. Note: the cherry-picked test file (`user-permissions.service.spec.ts`) was converted from `vitest` to `jest`, since this branch still uses jest for `@comet/cms-api`. No other changes were needed on top of the cherry-pick. **Verification on this branch:** - `pnpm --filter '@comet/cms-api' run build` — passes - `pnpm run lint` (in `packages/api/cms-api`) — passes - `pnpm exec jest src/user-permissions/user-permissions.service.spec.ts` — passes - `demo/api` boots and initializes `AppModule`/`GraphQLModule` correctly with the change (verified up to the expected Postgres connection error, since this sandbox can't pull Docker images to run the full demo) --- _Generated by [Claude Code](https://claude.ai/code/session_012tKRdTMdhcfvHVrZdrBFz8)_ Co-authored-by: VPS - Franz Unger <franz.unger@vivid-planet.com> Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
When the admin queries the users list (
userPermissionsUsers), thecontentScopesCountfield resolver runs once per row. Each invocation callsgetContentScopes(user), which recomputes the full list of available content scopes (build labels +uniqWithdeduplication) from scratch. For a page of users this repeats the same shared computation N times, which becomes very slow when a project configures many content scopes.Solution
Resolve the available content scopes once per request by routing
contentScopesCountthrough a request-scopedDataLoader(UserContentScopesLoaderService), following the existing DataLoader pattern in cms-api (e.g.AttachedDocumentLoaderService). All users of a request are batched into a singlegetContentScopesForUsers(users)call that computes the available content scopes only once and then maps each user's scopes.This PR keeps the existing
lodash.uniqWithdeduplication unchanged — the only change is how often the available content scopes are computed.Speed comparison (25 users)
Measured by resolving
contentScopesCountfor 25 users (median of 3 runs), comparing the current per-row behavior against the DataLoader:Typical case — each user resolves to a few content scopes
Worst case — every user resolves to all content scopes (the per-user
uniqWith, which this PR does not change, then dominates in both variants):So the DataLoader removes 24 of 25 redundant available-content-scope computations per request; the remaining cost is the per-user work, which is unchanged.
Example / test
user-permissions.service.spec.tscovers the batching guarantee (available content scopes computed only once for all users) and that each user's scopes are returned in input order.Notes
Supersedes #5999 (which additionally replaced the
uniqWithdeduplication with a custom algorithm). This PR isolates just the DataLoader change.https://claude.ai/code/session_01RGR2hkqpqcXL4xk7rGqz7n