newrelic/newrelic-python-agent

NR can't ASGI wrap Django Channels

rivte2 opened this issue · 3 comments

rivte2 commented

Description
Trying to use NR to wrap my Django Channels application that is running under Guicorn using Uvicorn workers. ASGIApplicationWrapper() is not working, it never hits to code that allows NR to build up the transaction handler.

Code in question is (asgi.py):

channel_layer = newrelic.agent.ASGIApplicationWrapper(get_default_application())

Which of course is invoked by Gunicorn via:

--worker-class uvicorn_worker.Worker asgi:channel_layer

Expected Behavior
Async/Channels is working perfectly, but when I attempt to wrapper it it seems the ASGI Handler is being wrapped by Uvicorn instead, first.

    scope = _bind_scope(*args, **kwargs)

    if scope["type"] != "http":          # <<----- scope http is not found (already wrapper'ed by uvicorn)
        return wrapped(*args, **kwargs)

See the image below from the debugger...

Troubleshooting or NR Diag results

asgi_application py 2023-11-17 10-30-15

Steps to Reproduce
Create a simple Django Channels application and try to use ASGIApplicationWrapper() to get NR to to start

Your Environment
newrelic-9.2.0
Django==4.2.5
gunicorn==20.1.0
uvicorn==0.23.2

Additional context
https://forum.newrelic.com/s/hubtopic/aAX8W000000L5mVWAS/python-asyncio-eventloop-monitoring-not-working?transfer=%253Atrue%253F#-66

Hello,

Is this application using http at all? Or entirely just websockets?

My experience with Django channels was that the actual HTTP parts were automatically wrapped, with no manual ASGI wrapper needed. The websockets, however, are not something we currently support monitoring out of the box. ASGI Web Transactions refuse to start automatically for websocket connections.

rivte2 commented

Just WebSockets. We are running uWSGI for HTTP. Any ideas how we can implement this to get a complete picture of the eventloop? BackgroundTask helps us look at slices but not the whole picture.

The general consensus about websockets has been that we don't have a clear point to call the start and the end of a user's interaction, and as a result can't reliably start and stop transactions in a meaningful way. It's entirely dependent on the implementation of the service.

The good news is that if you can clearly define that in your code you can use background tasks to get transaction data, and if you need finer grained slices you can use our other tracing APIs such as the function trace.