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
Instrumentation query hooks bug + teardown behaviour #1083
Comments
cc @exAspArk too since this affects apollo-tracing |
Thinking about this more, I don't think an instrumenter's So I'm not sure what or even if there's a solution to this. At a minimum the instrumentation docs should be updated to warn not to rely on state. Beyond that, should an exception in one instrumenter's We could just rescue when calling each |
These are great questions. I'm open to a lot of the solutions here and I agree, it's a bit murky in any case! I will think about this more tomorrow ... Happy to take a recommendation 😅 |
I'm curious what you're thinking of here?
If a before_query raises, should the query even execute or should that just bubble up immediately? I suppose it's good to be robust to bad instrumentation, but sometimes the instrumentation may be important and the query won't execute properly without it anyway... |
I guess any examples of using them independently could just be accomplished by putting code before or after you call
My initial thought is the exception should be raised right away and the query shouldn't execute. @rmosolgo it's kind of interesting you refer to One solution is just removing |
👍 please don't swallow exceptions :) By the way, is it possible to introspect queries similarly to fields (or middlewares)? So, developers could define whether it's important for them to "teardown" after getting an exception or not? For example: class MyInstrumenter
def instrument(query)
my_before_query
execute(query)
my_after_query
ensure
my_teardown
end
end |
It gets complicated when we run multiple queries together: http://graphql-ruby.org/queries/multiplex.html Should an error in one query cause the others to crash? Probably not, but maybe we can keep from running that one query. But multiplexing is why |
I don't see why the semantics shouldn't just be instrumenter1.before_query(query)
begin
instrumenter2.before_query(query)
begin
# ...
ensure
instrumenter2.after_query(query)
end
ensure
instrumenter1.after_query(query)
end as in the after_(query|multiplex) for an instrumenter should be called if its before_(query|multiplex) completes, regardless of any exceptions in other instrumenters or queries. That would preserve the intended teardown behaviour. Otherwise, another type of hook is needed for teardown (e.g. around_(query|multiplex)) to support this common use case. Recursion could be used to do the same thing with an array of instrumenters def call_query_hooks(instrumenters, query, i=0)
if i >= instrumenters.length
yield
else
instrumenters[i].before_query(query)
begin
call_query_hooks(instrumenters, query, i + 1) { yield }
ensure
instrumenters[i].after_query(query)
end
end
end |
That semantic seems good to me, any objections? Otherwise I'll implement it! |
I think that's the most logical behaviour 👍 The goal is still to isolate that within a multiple query I assume? |
Took a crack at it in #1100 |
We're seeing some surprising behaviour when using query level instrumentation. This might have been a naive assumption, but we assumed that the sequence of
before_query
->after_query
would be reliable.I've created a failing test case to demonstrate our situation: https://github.com/swalkinshaw/graphql-ruby/blob/45351d42dded3b682b59561b2ceb845d68b6d91c/spec/graphql/instrumentation_spec.rb
Summary:
before_query
(or maybe even during execution)before_query
in itsafter_query
hook which causes an errorRuntimeError: bad teardown
gets raised instead ofNameError
.The last point is especially confusing. The earlier exception is swallowed even though it happens first.
Basically, any instrumentation can't rely on state that's set in
before_query
being available inafter_query
if you have multiple instrumenters.Here's an example in the wild: https://github.com/uniiverse/apollo-tracing-ruby/blob/master/lib/apollo_tracing.rb
This one relies on the existence of a key (
apollo-tracing
) in the query context. This could easily cause problems if you had another instrumenter.Right now we've worked around this by ensuring any state we need actually exists but this seems like something the gem should ideally handle properly.
cc @eapache
The text was updated successfully, but these errors were encountered: