newrelic-python-agent: Issue running starlette: TypeError: _run_asgi2() takes 2 positional arguments but 4 were given
I am getting the following traceback when trying to launch an asgi server with starlette:
I am using this run command: newrelic-admin run-program gunicorn -w 4 -k uvicorn.workers.UvicornWorker my_package:app
Traceback (most recent call last):
File "/app/.heroku/python/lib/python3.8/site-packages/uvicorn/protocols/http/httptools_impl.py", line 391, in run_asgi
result = await app(self.scope, self.receive, self.send)
File "/app/.heroku/python/lib/python3.8/site-packages/uvicorn/middleware/proxy_headers.py", line 45, in __call__
return await self.app(scope, receive, send)
File "/app/.heroku/python/lib/python3.8/site-packages/newrelic/api/asgi_application.py", line 387, in nr_async_asgi
return await coro
File "/app/.heroku/python/lib/python3.8/site-packages/newrelic/common/async_proxy.py", line 148, in __next__
return self.send(None)
File "/app/.heroku/python/lib/python3.8/site-packages/newrelic/common/async_proxy.py", line 120, in send
return self.__wrapped__.send(value)
File "/app/.heroku/python/lib/python3.8/site-packages/newrelic/api/asgi_application.py", line 387, in nr_async_asgi
return await coro
File "/app/.heroku/python/lib/python3.8/site-packages/newrelic/common/async_proxy.py", line 148, in __next__
return self.send(None)
File "/app/.heroku/python/lib/python3.8/site-packages/newrelic/common/async_proxy.py", line 120, in send
return self.__wrapped__.send(value)
File "/app/.heroku/python/lib/python3.8/site-packages/starlette/applications.py", line 111, in __call__
await self.middleware_stack(scope, receive, send)
File "<string>", line 5, in wrapper
File "/app/.heroku/python/lib/python3.8/site-packages/starlette/middleware/errors.py", line 181, in __call__
raise exc from None
File "/app/.heroku/python/lib/python3.8/site-packages/starlette/middleware/errors.py", line 159, in __call__
await self.app(scope, receive, _send)
File "/app/.heroku/python/lib/python3.8/site-packages/newrelic/hooks/framework_starlette.py", line 108, in middleware_wrapper
return await FunctionTraceWrapper(wrapped, name=name)(*args, **kwargs)
File "/app/.heroku/python/lib/python3.8/site-packages/newrelic/api/function_trace.py", line 150, in literal_wrapper
return wrapped(*args, **kwargs)
TypeError: _run_asgi2() takes 2 positional arguments but 4 were given
Using:
newrelic==5.24.0.153
starlette==0.13.8
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Reactions: 4
- Comments: 32 (12 by maintainers)
Why has this been marked as wontfix? We are having the same issue and even trying the alternative method (here: https://docs.newrelic.com/docs/apm/agents/python-agent/installation/python-agent-advanced-integration/#manual-integration ) we have exactly the same error. Basically we have no way to use New Relic in our application because we are also using Sentry.
This is still an issue for us with similar circumstances.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Is this truly a wontfix? We are currently running into this with one of our FastAPI projects, and don’t want to have to make a choice between NewRelic and Sentry.
This is still an issue for us too, while we are using ASGI middleware for sentry and New Relic as monitoring service.
@cancan101 While we investigate, you should be able to work around this issue by forcing all requests to be treated as ASGI v3 by adding this patch:
This forces the
_run_asgi2call to run the_run_asgi3method instead.Example app:
still an open issue. don’t want to drop newrelic.
I think sentry-python v1.8.0 release fixes this!
Should add one comment. The reason that wrapt gives the correct results is that
inspect.iscoroutinefunction()andinspec.iscoroutine()internally useisinstance()checks. With wraptisinstance()checks actually work against the original wrapped type, as well as the wrapper, so the lookups done for subsequent to those checks appears to work. So my original comments saying they likely wouldn’t work was wrong just because of how they were implemented.Neither the wrapt
ObjectProxyorFunctionWrapperwhich derives from it have any support for proxying async functions. Thus if using theinspectfunctions on a wrapper and you ask whether the wrapped function is async, you will get the wrong result if it is.The
callable(),inspect.iscoroutine()andinspect.iscoroutinefunction()functions are problematic in a proxy object because if you wrap something which isn’t any of them, yet add the proxy functions, the tests on the wrapper will always say the wrapped object is a function or async function even if they aren’t.This is why the base
ObjectProxydoesn’t have a proxy for__call__()and if you know you are wrapping a function you must useFunctionWrapperwhich does. There is no separateAsyncFunctionWrapperobject for async functions, but even if there was it would be complicated to know when to use it versus a normal function wrapper in a generic system where over versions of the software being wrapped, what is used can change.The only possible solution have thought might be able to use to resolve the problem is to have the constructor for the proxy object perform a check whether a normal function, async function is passed and add extra proxy functions to the wrapper instance in that case for async.
Complicating this though is that you also have async generators and async context managers, so you need to look for the presence of each specific possible async dunder method and create a proxy function for each one as found. This will create a bit of overhead on construction and overhead may mount up over time if done on the generic project.
For
FunctionWrapperat least, since should know only dealing with a function, it may be enough to look for just__await__()and add a proxy function for it to the wrapper instance. I have no idea right now how async instance methods complicate this though.So suggest adding to the newrelic FunctionWrapper equivalent a constructor which checks for
__await__on what is being wrapped, and if there is, add a proxy function for it. Not sure if this is enough though for async instance methods as may need to be add support down in wrapt directly in the special_FunctionWrapperBaseandBoundFuntionWrappertypes.Anyway, since not really been devoting any time to improving wrapt, I have been ignoring the whole async issues for a very long time now. So this isn’t the only related issue.
Ability to put time in on this is a bit complicated right now.
I am also using this middleware which seems to be causing the issue: https://github.com/mfreeborn/fastapi-sqlalchemy/blob/39e7e8bb5d98a9de5fc365adf4bdc661d824b614/fastapi_sqlalchemy/middleware.py#L18-L45 I have it added after sentry in the list.