Skip to content

Speed up resolver method lookup for large schemas - #837

Merged
oryan-block merged 2 commits into
masterfrom
bugfix/541
Oct 4, 2026
Merged

oryan-block merged 2 commits into
masterfrom
bugfix/541

Conversation

@oryan-block

Copy link
Copy Markdown
Collaborator

Fixes #541

Checklist

  • Pull requests follows the contribution guide
  • New or modified functionality is covered by tests

Description

Schemas with a lot of root fields take minutes to build. The reporter in #541 has 5,611 Query and 16,461 Mutation fields, and finding their resolvers took 84s and 218s. FieldResolverScanner#findFieldResolver tries every root field on every root resolver. For each of those pairs, findResolverMethod rebuilt the resolver class's full method list (declared, superclass and interface methods) and then made up to five linear passes over it, building the candidate name (name, isName, getName, getFieldName, snake_case variant) again for every method. So the scan was roughly fields x resolvers x methods. JFR on master put ~99% of the scan time in findResolverMethod, mostly list iteration and StringBuilder work.

The scanner now groups each class's methods by name once per scan and looks up the candidate names directly, in the same order as before. The cache is keyed by the class and whether it's the subscription root, which are the only inputs to getAllMethods besides the options. groupBy keeps the original method order within each name, so the method that gets picked, the argument checks and the error messages don't change. The cache lives on FieldResolverScanner, which SchemaClassScanner creates once per SchemaParserBuilder#scan, so it's thrown away with the scan and nothing is shared between schemas.

I timed SchemaParserBuilder#build with generated Java root resolvers. 60 resolvers x 80 fields (4,800 root fields) went from ~9-11s to under 1s. 200 resolvers x 110 fields (22,000 fields, about the size in the issue) went from ~247s to ~2-3s. The new test only checks the lookup order (exact name, isX only for Boolean fields, getX, getFieldX) since that's the logic I rewrote, so it passes on master too. I didn't add a timing test.

I didn't go with the parallelStream approach from the issue. The dictionary, queue and the rest of the state SchemaClassScanner builds up aren't thread-safe, which is most likely where the bogus "can never be accessed" / "no methods on it were used" warnings and the failed startup came from. Scanning is still single-threaded. What's left is fields x root resolvers with a small constant, mostly building the candidate names for each pair. Computing them once per field in findFieldResolver would probably cut another 2-3x, but I kept this one minimal. The queue phase (~4.4s in the report) isn't touched.

Behaviour change: none, apart from scanning being a lot faster for schemas with many root resolvers and fields. A scan now holds one name-indexed method map per resolver class, which is released when it finishes.

🤖 Generated with Claude Code

oryan-block and others added 2 commits October 3, 2026 18:20
Schema scanning got very slow for large schemas with many root
resolvers. Every root field is searched on every root resolver, and
each search recomputed all methods of the resolver class and then made
up to five linear passes over them, building the candidate method name
again for every method. That made scanning roughly fields x resolvers x
methods, so a schema with thousands of root fields took minutes to
start.

FieldResolverScanner now groups the methods of each class by name once
per scan, keyed by class and subscription filter, and looks up the
candidate names (name, isName, getName, getFieldName, snake_case
variant) directly. The resolution order and argument checks are
unchanged. The cache lives on the scanner, so it is discarded with the
scan and nothing is shared between schemas.

Fixes #541

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@sonarqubecloud

sonarqubecloud Bot commented Oct 4, 2026

Copy link
Copy Markdown

@oryan-block
oryan-block merged commit 088ecfa into master Oct 4, 2026
6 checks passed
@oryan-block
oryan-block deleted the bugfix/541 branch October 4, 2026 12:44
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.

Parallel get extended field definitions

1 participant