-
Notifications
You must be signed in to change notification settings - Fork 48
Open
Description
Issue
Since 6af129f (v 6.7.10) it seems the middleware does not manage asynchronous request properly using Django + Uvicorn
Context
Python 3.13
django==5.2.7
posthog==6.7.10
uvicorn==0.38.0
Workaround
While it does not work for me, I override the original Middleware to add this (note: the missing part of code is basically a copy-paste of the original methods):
class AsyncPosthogContextMiddleware(PosthogContextMiddleware):
"""
Asynchronous Django middleware to extract PostHog context from HTTP requests.
While the original PosthogContextMiddleware is supposed to manage both sync and async requests,
the call to request.user fails in async contexts.
"""
async def extract_tags_async(self, request): # <== New method
# type: (HttpRequest) -> Dict[str, Any]
tags = {}
(user_id, user_email) = await self.extract_request_user_async(request) # <== Changed line
... # Original lines
async def extract_request_user_async(self, request): # <== New method
user_id = None
email = None
user = await request.auser() # <== Changed line
if user and getattr(user, "is_authenticated", False):
try:
user_id = str(user.pk)
except Exception: # noqa: BLE001, S110 # pylint: disable=broad-except
pass
try:
email = str(user.email)
except Exception: # noqa: BLE001, S110 # pylint: disable=broad-except
pass
return user_id, email
async def __acall__(self, request):
# type: (HttpRequest) -> Awaitable[HttpResponse]
"""
Asynchronous entry point for async request handling.
This method is called when the middleware chain is async.
"""
if self.request_filter and not self.request_filter(request):
return await self.get_response(request) # <== Changed line
... # Original linesI know this is bad and not future-proof, but I did not found a better way to switch to async nicely (ie, without wrapping everything inside sync_to_async) while preserving the original middleware.
Traceback
Traceback (most recent call last):
File "/.venv/lib/python3.13/site-packages/posthog/contexts.py", line 126, in new_context
yield
File "/.venv/lib/python3.13/site-packages/posthog/integrations/django.py", line 219, in __acall__
for k, v in self.extract_tags(request).items():
~~~~~~~~~~~~~~~~~^^^^^^^^^
File "/.venv/lib/python3.13/site-packages/posthog/integrations/django.py", line 117, in extract_tags
(user_id, user_email) = self.extract_request_user(request)
~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
File "/.venv/lib/python3.13/site-packages/posthog/integrations/django.py", line 174, in extract_request_user
if user and getattr(user, "is_authenticated", False):
^^^^
File "/.venv/lib/python3.13/site-packages/django/utils/functional.py", line 251, in inner
self._setup()
~~~~~~~~~~~^^
File "/.venv/lib/python3.13/site-packages/django/utils/functional.py", line 404, in _setup
self._wrapped = self._setupfunc()
~~~~~~~~~~~~~~~^^
File "/.venv/lib/python3.13/site-packages/django/contrib/auth/middleware.py", line 40, in <lambda>
request.user = SimpleLazyObject(lambda: get_user(request))
~~~~~~~~^^^^^^^^^
File "/.venv/lib/python3.13/site-packages/django/contrib/auth/middleware.py", line 20, in get_user
request._cached_user = auth.get_user(request)
~~~~~~~~~~~~~^^^^^^^^^
File "/.venv/lib/python3.13/site-packages/django/contrib/auth/__init__.py", line 311, in get_user
user = backend.get_user(user_id)
File "/.venv/lib/python3.13/site-packages/django/contrib/auth/backends.py", line 232, in get_user
user = UserModel._default_manager.get(pk=user_id)
File "/.venv/lib/python3.13/site-packages/django/db/models/manager.py", line 87, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
File "/.venv/lib/python3.13/site-packages/django/db/models/query.py", line 629, in get
num = len(clone)
File "/.venv/lib/python3.13/site-packages/django/db/models/query.py", line 366, in __len__
self._fetch_all()
~~~~~~~~~~~~~~~^^
File "/.venv/lib/python3.13/site-packages/django/db/models/query.py", line 1949, in _fetch_all
self._result_cache = list(self._iterable_class(self))
~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/.venv/lib/python3.13/site-packages/django/db/models/query.py", line 91, in __iter__
results = compiler.execute_sql(
chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size
)
File "/.venv/lib/python3.13/site-packages/django/db/models/sql/compiler.py", line 1621, in execute_sql
cursor = self.connection.cursor()
File "/.venv/lib/python3.13/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.
Metadata
Metadata
Assignees
Labels
No labels