-
Notifications
You must be signed in to change notification settings - Fork 179
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
Graphql query resolution gets very slow with middlewares. #708
Comments
This may help me - https://pypi.org/project/graphql-utilities/0.1.0/ |
A slightly modified version of run_only_once that works well for me, although I modified it to run once per request (rather than per operator) as I needed it for checking if the user is authenticated.
|
Speaking from few years of experience I feel that whatever you want to in GraphQL, middlewares are the worst way to go about it. Python utility that takes schema, function and selector, then calls function against resolver of every field matched by selector would run only on service's startup (vs on every query like how middleware classes are) and then only decorates specified fields (so there aren't bazillions of function calls), something like this: def require_auth(field, resolver):
if field.name in ["auth", "login"]:
return # return default resolvers on auth field and login mutation
@wraps(resolver)
def require_auth(obj, info, *args, **kwargs):
if not has_auth(info.context):
return None
return resolver(obj, info, *args, **kwargs)
return require_auth(resolver)
schema = wrap_resolvers(schema, require_auth, "Query>*,Mutation>*")
|
We ran into the same issue, we didn't know (it's not intuitive) that graphql-core changes EVERY single resolver to your middleware, so even if you have a simple attribute or dict value lookup, the middleware will run as many times as many properties your object has. In our case, more than 20,000 extra coroutines have been created, which slowed everything down by 4-5x. For authentication, we went down one level abstraction and wrote a Starlette middleware, so every query is authenticated only once. If you need any middleware functionality, I suggest doing the same and using Starlette middleware instead of graphql-core middlewares. |
ASGI middleware is the way to go for auth. GraphQL middlewares are more often a trap than useful solution. |
I'll label this as doc. We should bring this up as a warning. |
I'll add section about performance impact of middlewares to our docs. Thanks for bringing this up! |
We measured the impact of turning simple functions into coroutines and the slowdown is 100x (😱) so I don't think you can use this "middleware every resolver" without a serious performance hit. |
While debugging performance issues with queries that return a long list, I found that my middleware was causing a lot of slowness. At which point I reduced my middleware to a bare-bones middleware like this
With this middleware, a nested query below takes ~27 seconds. Without it, it takes 5 seconds!
can return a long list of service patterns and stops (~10,000 items).
Am I just paying the price of that extra function call? Or because I am awaiting every resolver in the middleware?
The text was updated successfully, but these errors were encountered: