-
-
Notifications
You must be signed in to change notification settings - Fork 564
Load types in schema on demand #69
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
Comments
This was added as experimental feature in v0.9.0, but unfortunately it doesn't work out of the box: eager type loading is still the default. One might override it by providing Release v0.9.0 contains experimental
$descriptor = $schema->getDescriptor();
file_put_contents($baseDir . '/my-schema-descriptor.php', "<?php\n return " . var_export($descriptor, true));
$descriptor = include $baseDir . '/my-schema-descriptor.php';
$typeLoader = function($typeName) {
$className = 'MyNamespace\\' . $typeName;
return new $className();
};
$lazyTypeResolutionStrategy = new GraphQL\Type\LazyResolution($descriptor, $typeLoader);
$schema = new GraphQL\Schema([
// ...
'typeResolution' => $lazyTypeResolutionStrategy
]); This is experimental feature, there are still no benchmarks to see if it gives major benefits. So until we do have some evidence that it helps - it may be a subject to change. |
Forgot to post results of my research on why trully lazy type loading is problematic (without external hints about schema structure) and what we will have to sacrifice to implement it: The most important problem: we must either sacrifice validation of fragment spreads in some cases or introduce type loader (similar to classloader in PHP). Consider this schema:
And query:
We don't know actual return type of We solved similar problem previously with Options are:
But even with type loader we will have to give up validating fragment spreads when fragment is of Interface type and it is spread on field or other fragment of interface type:
Right now if two interfaces have intersecting implementations this query will validate, but if not - it will fail the validation. With lazy approach it will always pass the validation, but then return nothing. I guess this case is extreemly rare. One more problem I've discovered is that we will have to force In general these trade-offs seem a reasonable price, but require major version dump. Also the type loading solution requires some further thinking. Re-opening this just to keep visible for next version. |
Meaning in it's current implementation this has not been done and something is broken? Could you elaborate on what is broken? I understand the example with Pet and Being is that the only thing?
Would you be able to post the benchmarks you've found? |
@AndreasHeiberg Current implementation works, but it requires separate build step. Basically you must analyze whole schema and save somewhere all types existing in schema and (most important) all interface implementations. Current solution requires these hints for lazy type loading. In theory, it is possible to prepare other solution which will load types on deman without separate build step. But such solution will have one restriction: you won't know all interface implementations. So any code that relies on this knowledge (like |
I just added LazyLoading in a project to gather some benchmarks. I did see a substantial 20% improvement for a small query only touching a tiny fraction of our schema. I was about to test more complicated queries that touch more of our schema only discover what I think is this case? I must have been optimistic when reading your initial comment. Is what you mean that the following should fail accordingly:
Running a query against this to the effect of:
Returns:
This is not a small edge case nor extremely rare our schema has this all over :( any suggestions for how this could be fixed? |
As for performance improvement - it should be quite constant in ms accross queries. Technically it saves time on schema building, so query size is not that important (but the impact will be smaller on bigger queries, simply because they do init more types during execution). As for the interface issue. This is not the same case as I described. You spread object types on interface field, but the case I described relates to spreading interface type on field of other interface type. So your example should always work - in both old and new anticipated solution. Given your result - it is either a bug in current solution or some error in your custom code. If you're sure this is bug - can you create reproducible test case and open new issue? (I need to see data and resolvers to figure out what's going on) |
Right opened #138 PR as I thought it would be more clear for the reduced test case. But yeah seemingly it is a problem with the current implementation and not my custom setup. Unless you see an issue with my reduced test case? |
@olragon Thanks for sharing this! Performance improvement is proportional to schema size (number of types and fields). I am not sure, but having |
Finally, the new implementation doesn't require a separate build step. Only type loader passed directly to schema. Will be released soon in v0.10.0. |
Currently all types (including all fields) are loaded on schema instance creation.
It is suboptimal for PHP, but it works this way because in some cases we need to know all interface implementors (for validation purposes - both in Validator and in Executor). And the only way to find them is to loop through all types and check if type implements given interface. Hence all types must be loaded for interface-related checks.
The goal of this task is to find a way for lazy-loading types in schema. This is possible, yet requires additional hints from user-land code to work efficiently (e.g. #40).
The text was updated successfully, but these errors were encountered: