Query validation never finishes on queries with many directives
alexus37 opened this issue · 3 comments
Describe the bug
Hi,
I have an artificial test case which creates a query with many (non- existing) directives in a query.
If I call .valid?
on this query the computation never finishes. This was very fast in 2.1
max_byte_size = 1_000_000
max_directive_count = 100
query_string = "query { viewer { login #{ "@a" * (max_byte_size / 2 - 50) } } }"
document = GraphQL.parse(query_string, tracer: tracer)
query = GraphQL::Query.new(
schema,
document: document,
context: context,
variables: variables,
validate: validate,
)
query.valid? # never finishes
Versions
graphql
version: 2.2.14
graphql-pro
version: 1.27.0
Steps to reproduce
See the the code above.
Expected behavior
This should return static validation errors fast.
Actual behavior
The validation should finish fast.
Hi! sorry for the trouble. I would also expect it to return quickly. I wrote a script based on your example code, but for me, it was faster in 2.2 than 2.1:
Validating lots of undefined directives
require "bundler/inline"
gemfile do
gem "graphql", "~>2.3.0" # or 2.1, 2.2
end
max_byte_size = 1_000_000
max_directive_count = 100
class MySchema < GraphQL::Schema
class User < GraphQL::Schema::Object
field :login, String
end
class Query < GraphQL::Schema::Object
field :viewer, User
end
query(Query)
end
query_string = "query { viewer { login #{ "@a" * (max_byte_size / 2 - 50) } } }"
document = GraphQL.parse(query_string)
query = GraphQL::Query.new(
MySchema,
document: document,
)
puts "GraphQL-Ruby v#{GraphQL::VERSION} Starting"
pp query.valid?
puts "Done"
Output:
v2.3.2, 1.92 seconds:
~/code/graphql-ruby $ time ruby directive_test.rb
GraphQL-Ruby v2.3.2 Starting
false
Done
ruby directive_test.rb 1.92s user 0.11s system 97% cpu 2.080 total
v2.2.14, 2.06 seconds:
~/code/graphql-ruby $ time ruby directive_test.rb
GraphQL-Ruby v2.2.12 Starting
false
Done
ruby directive_test.rb 2.06s user 0.15s system 94% cpu 2.336 total
2.1.11, 4.61 seconds:
~/code/graphql-ruby $ time ruby directive_test.rb
GraphQL-Ruby v2.1.11 Starting
false
Done
ruby directive_test.rb 4.61s user 0.20s system 98% cpu 4.859 total
Are there other details that might help me replicate this issue?
In the meantime, you could try:
- validation timeout: https://graphql-ruby.org/queries/timeout.html#validation-and-analysis
validate_max_errors
: https://graphql-ruby.org/errors/overview.html#validation-errors
Let me know what you think!
I did some research and discovered that it is connected to the opentelemetry-instrumentation-graphql
. Surprisingly, it runs quickly with version 2.1 but significantly slower with version 2.2. Check out the specifics of a script and the experiments conducted.
require "bundler/inline"
gemfile do
source 'https://rubygems.org'
gem "base64", "~>0.2.0"
gem "graphql", "~>2.1.11" # or 2.1, 2.2
gem 'opentelemetry-instrumentation-graphql', '~> 0.28.0'
gem 'opentelemetry-sdk', '~> 1.0'
end
max_byte_size = 1_000_000
max_directive_count = 100
class MySchema < GraphQL::Schema
class User < GraphQL::Schema::Object
field :login, String
end
class Query < GraphQL::Schema::Object
field :viewer, User
end
query(Query)
trace_with GraphQL::Tracing::CallLegacyTracers
end
OpenTelemetry::SDK.configure do |c|
c.use_all('OpenTelemetry::Instrumentation::GraphQL' => { schemas: [MySchema] })
end
query_string = "query { viewer { login #{ "@a" * (max_byte_size / 2 - 50) } } }"
document = GraphQL.parse(query_string)
query = GraphQL::Query.new(
MySchema,
document: document,
)
puts "GraphQL-Ruby v#{GraphQL::VERSION} Starting"
t0 = Time.now
pp query.valid?
puts "Took: #{Time.now - t0}"
Output:
2.1
GraphQL-Ruby v2.1.12 Starting
false
Took: 1.371169
2.2
GraphQL-Ruby v2.2.14 Starting
false
Took: 248.905892
Hey, thanks for sharing that replication script. I identified the regression in the implementation of Node#line
and Node#col
which are used when preparing error JSON. I improved the implementation in #4949 and released the fix in 2.3.3.
Does updating to that new version work for you?