Skip to content

Write a new execution module for GraphQL-Ruby #5507

@rmosolgo

Description

@rmosolgo

I have been spending a lot of time trying to move the existing execution code forward in a compatible way, but I'm finding it impossible :S I mean at least these modules:GraphQL::Execution::Interpreter, Interpreter::Runtime, Interpreter::Arguments (and HasArguments, ArgumentValue), Dataloader, Execution::Lazy.

Writing up all the details is possible but in the interest of getting started, I'll be brief:

  • Performance: A lot of possible performance gains have been identified (Memoize selection gathering #5502, Supporting Batch Resolvers in GraphQL-Ruby #5446, Don't check every returned object for lazy? #4426) but are stuck in compatibility land for edge cases
  • Correctness: GraphQL-Ruby has received a lot of features over the years, tacked on in different ways. They don't always work right together... it's worth considering which ones can be jettisoned for other approaches (field extras?) or merged together, at least under the hood (prepare:, loads:, validates:?).
  • Features: actually, performance is the feature that I'd want from this. I expect most features could be reimplemented one way or another -- or at least a very clear migration path -- with a new core runtime.

So, I'm proposing a project like:

  • Build a new runtime in isolation (takes the same inputs as Schema.run, returns the same output; can be used on a query-by-query basis for Scientist-like checks)
  • Make sure the new runtime checks the necessary boxes (see below)
  • One at a time, reimplement existing features to the degree possible
  • Also build a "GraphQL Doctor" which inspects source code and schemas in memory and outputs the result of compatibility checks and links to migration notes

After trying and trying, I don't think a future execution paradigm can be achieved with a perfectly smooth path, but I think it's worth pursing -- Shopify has been using custom execution code to great success for a while now.

New Execution Goals in no specific order:

cc @gmac since you've been investigating a lot of these too -- what do you think this approach to improving GraphQL-Ruby?


Appendix: essential and non-essential forwards-compatible features

These are things that must have good enough compatibility that a given application can switch between runtimes on a query-by-query basis:

  • Everything in the GraphQL spec (including null propagation, @skip/@include, static validation (same code))
  • Query analyzers (same code used in both cases)
  • Custom scalars
  • Resolver classes
  • Dataloader
  • GraphQL-Batch support
  • Schema visibility (same code should work in this new runtime, since it's applied during static validation)
  • Multiplex: I expect this to basically work fine in the new flow with a bit of work.
  • ... I will add other things here as I encounter them

Then there are some features whose forward compatibility I don't consider to be essential. In these cases, supporting both runtimes in your schema might require de-customizing (ie, moving behavior into your app code or into a resolver). However I bet they'll eventually be able to be reimplemented in a very compatible way, and I expect them to be easily identifiable by "GraphQL Doctor":

  • Argument loads:, prepare:, validates:
  • Field extras, extensions
  • Custom context and query classes
  • GraphQL::Schema::Object .wrap(...), .authorized?: I expect the object lifecycle to change here. At a minimum, it will be required to opt into YourObjectType.new ever being called. There will definitely be some future implementation of runtime authorized checks, but they'll have to be different because of the different execution flow.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions