Defer directive by rmosolgo · Pull Request #168 · rmosolgo/graphql-ruby
The big todo before putting this in master is fixing this problem:
Tests which depend on SerialExecution are littered throughout the test suite. For example, "non_null_type_spec.rb" contains tests about how null values are handled during execution. Both SerialExecution and DeferredExecution need to pass this test, so, how can we make that happen? I can think of two approaches, or maybe three:
- Parameterize the test suite. Accept an argument for which execution strategy to test, eg
rake test DEFAULT_EXECUTION=DeferredExecution. This seems easiest to implement but introduces a weird "gotcha" to the test suite. - Extract execution-dependent tests into a module, then include that module into both
serial_execution_testanddeferred_execution_test. This is good -- code sharing is done with Ruby rather than a weird workaround. - The real golden ticket would be to extract those tests into a module and put it in
lib/. In theory, execution strategies are part ofgraphql-ruby's public API, and I think it would be nice to provide "compliance tests" for any user-provided executor. As far as I know,graphql-batchis the only "third party" executor, so this is not a high priority. This approach also appeals to me in the parser department, as that would make it easier to keepgraphql-libgraphqlparserup-to-date.
I think eventually, DeferredExecution could replace SerialExecution altogether. It provides serial execution, but the "threaded" implementation is much more robust -- it even lays the groundwork for parallelism in multithreaded Rubies (sadly not part of my world). But I don't want to hose graphql-batch or its users, and that depends on SerialExecution. So, I'm thinking about rolling batching right into deferred execution, so that feature won't be lost. That will take some work :)
As for graphql-streaming, I think ActionCable support is experimental, to say the least, but ActionController::Live (which supports @defer and @stream, but not subscription) is ready to roll -- in fact, if you see the implementation, you'll see it's quite boring 😆.
There's one deficiency in the client, and I'm not sure how to beat it yet: when we receive incoming patches, we re-split the entire patch string, instead of just identifying the newly-added part. As the patch string grows, the cost of splitting it grows. I'm not sure how bad the cost is, but you can see the relevant lines here: https://github.com/rmosolgo/graphql-streaming/blob/master/lib/graphql/streaming/clients/graphql-streaming/streaming_graphql_client.js#L39-L41