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

Async view raises SynchronousOnlyOperation when also logged into Django admin #343

Open
ghost opened this issue Jul 27, 2022 · 7 comments
Open

Comments

@ghost
Copy link

ghost commented Jul 27, 2022

i.e., when you have the sessionid cookie.

The workaround is to log out of admin, or delete the sessionid cookie.

Traceback (most recent call last):
  File "/usr/local/lib/python3.8/site-packages/graphql/execution/execute.py", line 521, in execute_field
    result = resolve_fn(source, info, **args)
  File "/usr/local/lib/python3.8/site-packages/strawberry_django_plus/optimizer.py", line 573, in resolve
    ret = _next(root, info, *args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/strawberry_django_jwt/middleware.py", line 102, in resolve
    user = authenticate(request=context, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/django/views/decorators/debug.py", line 42, in sensitive_variables_wrapper
    return func(*func_args, **func_kwargs)
  File "/usr/local/lib/python3.8/site-packages/django/contrib/auth/__init__.py", line 77, in authenticate
    user = backend.authenticate(request, **credentials)
  File "/usr/local/lib/python3.8/site-packages/strawberry_django_jwt/backends.py", line 11, in authenticate
    return get_user_by_token(token, request)
  File "/usr/local/lib/python3.8/site-packages/strawberry_django_jwt/shortcuts.py", line 30, in get_user_by_token
    return get_user_by_payload(payload)
  File "/usr/local/lib/python3.8/site-packages/strawberry_django_jwt/utils.py", line 169, in get_user_by_payload
    user = jwt_settings.JWT_GET_USER_BY_NATURAL_KEY_HANDLER(username)
  File "/usr/local/lib/python3.8/site-packages/strawberry_django_jwt/utils.py", line 150, in get_user_by_natural_key
    return user_model.objects.get_by_natural_key(username)
  File "/usr/local/lib/python3.8/site-packages/django/contrib/auth/base_user.py", line 46, in get_by_natural_key
    return self.get(**{self.model.USERNAME_FIELD: username})
  File "/usr/local/lib/python3.8/site-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 492, in get
    num = len(clone)
  File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 302, in __len__
    self._fetch_all()
  File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 1507, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
  File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 57, in __iter__
    results = compiler.execute_sql(
  File "/usr/local/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 1359, in execute_sql
    cursor = self.connection.cursor()
  File "/usr/local/lib/python3.8/site-packages/django/utils/asyncio.py", line 24, in inner
    raise SynchronousOnlyOperation(message)
django.core.exceptions.SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.
@KundaPanda
Copy link
Owner

Hello,
Thanks for submitting the issue.

It looks to me as if you were using the ASGI app with the synchronous jwt middleware. Could you please verify that this is the case?

@ghost
Copy link
Author

ghost commented Jul 28, 2022

@KundaPanda We are using AsyncStatusHandlingGraphQLView with AsyncJSONWebTokenMiddleware

@KundaPanda
Copy link
Owner

@KundaPanda We are using AsyncStatusHandlingGraphQLView with AsyncJSONWebTokenMiddleware

Okay so that seems in order.

Are you running the app with an ASGI-capable server as well (daphne, uvicorn, hypercorn)? This seems like the second most likely cause (i.e. with the runserver command or gunicorn).

@ghost
Copy link
Author

ghost commented Jul 28, 2022

We've encountered the issue with runserver and runserver_plus

Haven't deployed with uvicorn yet.

Async seems to work though. I tested an API with asyncio.sleep(10) and hit it in 2 tabs.

@KundaPanda
Copy link
Owner

KundaPanda commented Jul 28, 2022

That explains it then. You need a proper ASGI server to send ASGI requests -- runserver and runserver_plus both serve WSGI only.

Internally this seems to work for you because Django creates a new loop for every incoming request. So you can have async views, but they are not actually running asynchronously. This also means that all Django middleware runs synchronously when processing requests. I will try to look into this and implement own asyncio loop creation in the middleware, but I do not consider this a bug/issue but rather a nice-to-have feature for debugging with runserver.

@nrbnlulu
Copy link

nrbnlulu commented Jul 28, 2022

If you use channels runserver would be asgi so you can just add channels as dev requirement..

@ghost
Copy link
Author

ghost commented Aug 25, 2022

Tested with uvicorn. Same error.

CMD [ "uvicorn", "mysite.asgi:application", "--host=0.0.0.0", "--port=8000", "--reload" ]

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

No branches or pull requests

2 participants