Skip to content
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

feat(GraphQL::Batch::SetupMultiplex) use multiplex instrumentation to share a batching context #57

Merged
merged 2 commits into from
Jul 24, 2017

Conversation

rmosolgo
Copy link
Contributor

@rmosolgo rmosolgo commented Jun 6, 2017

This patch adds support for a shared batching context when multiple queries are run concurrently. Is it something you're interested in for this gem?

Single queries are still supported because graphql 1.6+ treats Schema#execute as a special case of Schema#multiplex: a multiplex with one query. So it's still covered by instrument(:multiplex,...).

Copy link
Contributor

@dylanahsmith dylanahsmith left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for trying to add support for this. I'm just a little bit concerned about the order of operations.

}
GRAPHQL

results = schema_multiplex([
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can just use Schema.multiplex directly. The reason test/graphql_test.rb has a schema_execute method is that execution_strategy_test.rb overrides it to do the same tests.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm OK with merging this PR after this nitpick is addressed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤦‍♂️ Sorry I forgot about this feedback all this time! I just pushed a fix for it.

assert_equal expected_1, results.first
assert_equal expected_2, results.last
assert_equal ["Product/1,2,3"], queries
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried making the following changes to the test

diff --git a/test/multiplex_test.rb b/test/multiplex_test.rb
index c120614..6748aab 100644
--- a/test/multiplex_test.rb
+++ b/test/multiplex_test.rb
@@ -24,9 +24,15 @@ class GraphQL::MultiplexTest < Minitest::Test
         second: product(id: $id2) { id, title }
       }
     GRAPHQL
+    mutation_string = <<-GRAPHQL
+      mutation {
+        counter_loader
+      }
+    GRAPHQL
 
     results = schema_multiplex([
       { query: query_string, variables: { "id1" => "1", "id2" => "2"} },
+      { query: mutation_string, context: { counter: 0 } },
       { query: query_string, variables: { "id1" => "1", "id2" => "3"}},
     ])
 
@@ -39,13 +45,20 @@ class GraphQL::MultiplexTest < Minitest::Test
 
     expected_2 = {
       "data" => {
+        "counter_loader" => 0,
+      }
+    }
+
+    expected_3 = {
+      "data" => {
         "first" => { "id" => "1", "title" => "Shirt" },
         "second" => { "id" => "3", "title" => "Sweater" },
       }
     }
 
     assert_equal expected_1, results.first
-    assert_equal expected_2, results.last
+    assert_equal expected_2, results[1]
+    assert_equal expected_3, results.last
     assert_equal ["Product/1,2,3"], queries
   end
 end

and it still passed, even though there is a mutation in between the queries.

What should be the expectations around the ordering of the operations? The graphql-ruby multiplex documentation says it will "run queries concurrently", but also says this feature is for Apollo Client’s query batching which "is a transport-level mechanism" where I would expect the order of operations would be preserved.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a great point, and it's something I overlooked. It makes no special treatment for mutations, but it could. (Apparently the JS server doesn't make special treatment either: apollographql/apollo-server#176 (comment))

Maybe we could do a flow like this:

  • Shift the next operation from the set
    • If it's a mutation:
      • Run any already-gathered queries concurrently
      • Run it in isolation
    • If it's a query, add it to the next multiplex
  • When the set is empty:
    • Run any already-gathered queries concurrently

I think that would maintain the expected ordering for mutations: queries before mutations would not reflect their changes, but queries after mutations would reflect mutations.

However, now that I write it, I don't know if the incoming queries are ordered. Maybe they come as an unordered set.

If that's the case, maybe a better flow is mutate-then-read:

  • For each operation in the set, if it's a mutation, run its root fields
  • Then, fullfill all other fields concurrently.

That way, all reads in the multiplex reflect the changes of all mutations in the multiplex.

Hmm, what if the mutations are order-dependent? :head_explodes:

Copy link
Contributor

@dylanahsmith dylanahsmith Jun 8, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting, so it looks like they intentionally have the queries running in parallel according to the apollo server implementation. Given that, and the fact that graphql-ruby already follows that approach and documents it more clearly, I guess there is no need to be concerned about it here.

I suppose a client or a server could always choose to re-order the operations and multiplex/group them based on their desired semantics.

Hmm, what if the mutations are order-dependent? :head_explodes:

In that case I would put all the mutations in the same mutation query as separate field selections, although that is easier when using dynamic queries.

@etripier
Copy link

This is awesome! It fixes all the issues I was having integrating graphql-batch with react-apollo. Just chiming in to show interest in getting this merged. Thanks @rmosolgo!

@dylanahsmith dylanahsmith merged commit 69a14c5 into Shopify:master Jul 24, 2017
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.

3 participants