Various performance boosts in nests/graphql
PR Checklist
Please check if your PR fulfills the following requirements:
- [ ] The commit message follows our guidelines: https://github.com/nestjs/nest/blob/master/CONTRIBUTING.md
- [ ] Tests for the changes have been added (for bug fixes / features)
- [ ] Docs have been added / updated (for bug fixes / features)
PR Type
What kind of change does this PR introduce?
- [x] Bugfix
- [ ] Feature
- [ ] Code style update (formatting, local variables)
- [ ] Refactoring (no functional changes, no api changes)
- [ ] Build related changes
- [ ] CI related changes
- [ ] Other... Please describe:
What is the current behavior?
When bootstrapping a gql application, having many schemas results in a very large memory footprint. For our project with 200 schemas, we couldn't run the server because it consumed past 8GB memory and died on OOM.
Issue Number: N/A
What is the new behavior?
Reducing the amount of redundant compilations of the GQL data object model (metadata wise) is now possible because for the switch to map based metadata storage. Removing the redundant metadata assignments produces a tremendous reduction of memory usage (from 8GB+ to 700MB)
Does this PR introduce a breaking change?
- [ ] Yes
- [x] No
Other information
Hey @kamilmysliwiec, I've made some improvements that drastically reduce the memory footprint of a GQL server. Could you please verify and merge this?
-
getObjectOrInterfaceTypeNameIfExists - This function was not fixed on the move to map based metadata storage. Now instead of looking inside an entire metadata array, it fetches the item from the map
-
MetadataCollectionModel - I noticed that the interfaces list recieves duplicate instances of the same interface, so I switched the implementation to a map to remvoe duplicates.
-
LazyMetadataStorageHost.load - In very large applications (ie several millions of metadata object) we encountered an invalid arugments size thrown from V8, this is because the spread operator behind the scenes translates the values to multiple arguments. Switching to flat() solves this issue.
-
GraphQLSchemaFactory.create & LazyMetadataStorageHost.updateStorage - We noticed that the entire GQL metadata model was being rebuilt several times during the bootstrap of the application, I assume this was done because of the need to clear and rebuild the arrays every time. Now when we use maps we can't get duplicates in the metadata store, so I verify that the updateStorage callback is called only once, and I removed the clear call from the GraphQLSchemaFactory.create(). This results in a tremendous memory consumption boost! (in our case, from 8GB to 700MB)

Build is broken now @roypeled