emmett-framework / granian

A Rust HTTP server for Python applications
BSD 3-Clause "New" or "Revised" License
2.86k stars 83 forks source link

ASGI flow error using websockets #414

Closed estyrke closed 1 month ago

estyrke commented 1 month ago

I get this error using FastAPI with granian (possibly related to #186). Repro:

import granian
from fastapi import FastAPI
from granian.constants import Interfaces

app = FastAPI()

def run():
    granian.Granian(
        target=f"{__name__}:app",
        address="0.0.0.0",
        port=8000,
        interface=Interfaces.ASGI,
    ).serve()

if __name__ == "__main__":
    run()

Then just new WebSocket("ws://localhost:8000").connect in a browser console will trigger this error:

[ERROR] Application callable raised an exception
Traceback (most recent call last):
  File "/.venv/lib/python3.12/site-packages/granian/_futures.py", line 4, in future_watcher
    await inner(watcher.scope, watcher.proto)
  File "/.venv/lib/python3.12/site-packages/fastapi/applications.py", line 1054, in __call__
    await super().__call__(scope, receive, send)
  File "/.venv/lib/python3.12/site-packages/starlette/applications.py", line 113, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/.venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 152, in __call__
    await self.app(scope, receive, send)
  File "/.venv/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 62, in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
  File "/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 62, in wrapped_app
    raise exc
  File "/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 51, in wrapped_app
    await app(scope, receive, sender)
  File "/.venv/lib/python3.12/site-packages/starlette/routing.py", line 715, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/.venv/lib/python3.12/site-packages/starlette/routing.py", line 765, in app
    await self.default(scope, receive, send)
  File "/.venv/lib/python3.12/site-packages/starlette/routing.py", line 644, in not_found
    await websocket_close(scope, receive, send)
  File "/.venv/lib/python3.12/site-packages/starlette/websockets.py", line 195, in __call__
    await send({"type": "websocket.close", "code": self.code, "reason": self.reason})
  File "/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 48, in sender
    await send(message)
RuntimeError: ASGI flow error

Granian 1.6.0, FastAPI 0.115.2.

estyrke commented 1 month ago

I tried with uvicorn too, there I get a 403 response: INFO: ('127.0.0.1', 49425) - "WebSocket /" 403

It seems it has special handling when it gets "websocket.close" when the handshake is not completed.

estyrke commented 1 month ago

I should add that our application doesn't use websockets at all, and we have no code to handle websocket requests. We just noticed this crash, probably from some botnet trying to probe us.

gi0baro commented 1 month ago

@estyrke thank you for reporting thing. Gonna push a fix ASAP and include it in 1.6.1

Tragio commented 1 month ago
2024-10-13 18:02:37.467 | RuntimeError: ASGI flow error |  
-- | -- | --
  |   | 2024-10-13 18:02:37.467 | ^^^^^^^^^^^^^ |  
  |   | 2024-10-13 18:02:37.467 | result = task.result() |  
  |   | 2024-10-13 18:02:37.467 | File "/usr/local/lib/python3.12/site-packages/channels/utils.py", line 49, in await_many_dispatch |  
  |   | 2024-10-13 18:02:37.467 | await task |  
  |   | 2024-10-13 18:02:37.467 | File "/usr/local/lib/python3.12/site-packages/channels/utils.py", line 57, in await_many_dispatch |  
  |   | 2024-10-13 18:02:37.467 | await await_many_dispatch( |  
  |   | 2024-10-13 18:02:37.467 | File "/usr/local/lib/python3.12/site-packages/channels/consumer.py", line 58, in __call__ |  
  |   | 2024-10-13 18:02:37.467 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2024-10-13 18:02:37.467 | return await consumer(scope, receive, send) |  
  |   | 2024-10-13 18:02:37.467 | File "/usr/local/lib/python3.12/site-packages/channels/consumer.py", line 94, in app |  
  |   | 2024-10-13 18:02:37.467 | ^^^^^^^^^^^^^^^^^^ |  
  |   | 2024-10-13 18:02:37.467 | return await application( |  
  |   | 2024-10-13 18:02:37.467 | File "/usr/local/lib/python3.12/site-packages/channels/routing.py", line 132, in __call__ |  
  |   | 2024-10-13 18:02:37.467 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2024-10-13 18:02:37.467 | return await self.inner(scope, receive, send) |  
  |   | 2024-10-13 18:02:37.467 | File "/usr/local/lib/python3.12/site-packages/channels/middleware.py", line 24, in __call__ |  
  |   | 2024-10-13 18:02:37.467 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2024-10-13 18:02:37.467 | return await super().__call__(scope, receive, send) |  
  |   | 2024-10-13 18:02:37.467 | File "/usr/local/lib/python3.12/site-packages/channels/auth.py", line 185, in __call__ |  
  |   | 2024-10-13 18:02:37.467 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2024-10-13 18:02:37.467 | return await self.inner(wrapper.scope, receive, wrapper.send) |  
  |   | 2024-10-13 18:02:37.467 | File "/usr/local/lib/python3.12/site-packages/channels/sessions.py", line 263, in __call__ |  
  |   | 2024-10-13 18:02:37.467 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2024-10-13 18:02:37.467 | return await self.inner(dict(scope, cookies=cookies), receive, send) |  
  |   | 2024-10-13 18:02:37.467 | File "/usr/local/lib/python3.12/site-packages/channels/sessions.py", line 47, in __call__ |  
  |   | 2024-10-13 18:02:37.467 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2024-10-13 18:02:37.467 | return await self.application(scope, receive, send) |  
  |   | 2024-10-13 18:02:37.467 | File "/usr/local/lib/python3.12/site-packages/channels/security/websocket.py", line 37, in __call__ |  
  |   | 2024-10-13 18:02:37.467 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2024-10-13 18:02:37.467 | return await application(scope, receive, send) |  
  |   | 2024-10-13 18:02:37.467 | File "/usr/local/lib/python3.12/site-packages/channels/routing.py", line 62, in __call__ |  
  |   | 2024-10-13 18:02:37.467 | await inner(watcher.scope, watcher.proto) |  
  |   | 2024-10-13 18:02:37.467 | File "/usr/local/lib/python3.12/site-packages/granian/_futures.py", line 4, in future_watcher |  
  |   | 2024-10-13 18:02:37.467 | Traceback (most recent call last): |  
  |   | 2024-10-13 18:02:37.467 | [ERROR] Application callable raised an exception |  
  |   | 2024-10-13 18:02:23.466 | RuntimeError: ASGI flow error |  
  |   | 2024-10-13 18:02:23.466 | ^^^^^^^^^^^^^ |  
  |   | 2024-10-13 18:02:23.466 | result = task.result() |  
  |   | 2024-10-13 18:02:23.466 | File "/usr/local/lib/python3.12/site-packages/channels/utils.py", line 49, in await_many_dispatch |  
  |   | 2024-10-13 18:02:23.466 | await task |  
  |   | 2024-10-13 18:02:23.466 | File "/usr/local/lib/python3.12/site-packages/channels/utils.py", line 57, in await_many_dispatch |  
  |   | 2024-10-13 18:02:23.466 | await await_many_dispatch( |  
  |   | 2024-10-13 18:02:23.466 | File "/usr/local/lib/python3.12/site-packages/channels/consumer.py", line 58, in __call__ |  
  |   | 2024-10-13 18:02:23.466 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2024-10-13 18:02:23.466 | return await consumer(scope, receive, send) |  
  |   | 2024-10-13 18:02:23.466 | File "/usr/local/lib/python3.12/site-packages/channels/consumer.py", line 94, in app |  
  |   | 2024-10-13 18:02:23.466 | ^^^^^^^^^^^^^^^^^^ |  
  |   | 2024-10-13 18:02:23.466 | return await application( |  
  |   | 2024-10-13 18:02:23.466 | File "/usr/local/lib/python3.12/site-packages/channels/routing.py", line 132, in __call__ |  
  |   | 2024-10-13 18:02:23.466 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2024-10-13 18:02:23.466 | return await self.inner(scope, receive, send) |  
  |   | 2024-10-13 18:02:23.466 | File "/usr/local/lib/python3.12/site-packages/channels/middleware.py", line 24, in __call__ |  
  |   | 2024-10-13 18:02:23.466 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2024-10-13 18:02:23.466 | return await super().__call__(scope, receive, send) |  
  |   | 2024-10-13 18:02:23.466 | File "/usr/local/lib/python3.12/site-packages/channels/auth.py", line 185, in __call__ |  
  |   | 2024-10-13 18:02:23.466 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2024-10-13 18:02:23.466 | return await self.inner(wrapper.scope, receive, wrapper.send) |  
  |   | 2024-10-13 18:02:23.466 | File "/usr/local/lib/python3.12/site-packages/channels/sessions.py", line 263, in __call__ |  
  |   | 2024-10-13 18:02:23.466 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2024-10-13 18:02:23.466 | return await self.inner(dict(scope, cookies=cookies), receive, send) |  
  |   | 2024-10-13 18:02:23.466 | File "/usr/local/lib/python3.12/site-packages/channels/sessions.py", line 47, in __call__ |  
  |   | 2024-10-13 18:02:23.466 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2024-10-13 18:02:23.466 | return await self.application(scope, receive, send) |  
  |   | 2024-10-13 18:02:23.466 | File "/usr/local/lib/python3.12/site-packages/channels/security/websocket.py", line 37, in __call__ |  
  |   | 2024-10-13 18:02:23.466 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2024-10-13 18:02:23.466 | return await application(scope, receive, send) |  
  |   | 2024-10-13 18:02:23.466 | File "/usr/local/lib/python3.12/site-packages/channels/routing.py", line 62, in __call__ |  
  |   | 2024-10-13 18:02:23.466 | await inner(watcher.scope, watcher.proto) |  
  |   | 2024-10-13 18:02:23.466 | File "/usr/local/lib/python3.12/site-packages/granian/_futures.py", line 4, in future_watcher |  
  |   | 2024-10-13 18:02:23.466 | Traceback (most recent call last): |  
  |   | 2024-10-13 18:02:23.466 | [ERROR] Application callable raised an exception

Not sure if this is related @gi0baro, however, I have this Application callable raised an exception with frequency on Sentry. But in my case, I'm using Django and Django Channels 🤔

grant-oscillolabs commented 1 month ago

Very timely as I was looking into these errors today for our platform:

We are using websockets (purely for pushing notifications), but the flow error happens randomly and I don't have any ideas currently on how to debug it effectively. It doesn't appear to be impacting performance/useability (nothing reported anyway), but it'd be good to understand more about it.

2024-10-14T00:10:37.621926524Z [ERROR] Application callable raised an exception
2024-10-14T00:10:37.621976725Z Traceback (most recent call last):
2024-10-14T00:10:37.621985425Z   File "/usr/local/lib/python3.12/site-packages/granian/_futures.py", line 4, in future_watcher
2024-10-14T00:10:37.621992626Z     await inner(watcher.scope, watcher.proto)
2024-10-14T00:10:37.621998626Z   File "/usr/local/lib/python3.12/site-packages/channels/routing.py", line 62, in __call__
2024-10-14T00:10:37.622003926Z     return await application(scope, receive, send)
2024-10-14T00:10:37.622008926Z            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-10-14T00:10:37.622013726Z   File "/usr/local/lib/python3.12/site-packages/channels/security/websocket.py", line 37, in __call__
2024-10-14T00:10:37.622019426Z     return await self.application(scope, receive, send)
2024-10-14T00:10:37.622025026Z            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-10-14T00:10:37.622030226Z   File "/usr/local/lib/python3.12/site-packages/channels/sessions.py", line 47, in __call__
2024-10-14T00:10:37.622035426Z     return await self.inner(dict(scope, cookies=cookies), receive, send)
2024-10-14T00:10:37.622057427Z            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-10-14T00:10:37.622063227Z   File "/usr/local/lib/python3.12/site-packages/channels/sessions.py", line 263, in __call__
2024-10-14T00:10:37.622069627Z     return await self.inner(wrapper.scope, receive, wrapper.send)
2024-10-14T00:10:37.622075227Z            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-10-14T00:10:37.622079927Z   File "/usr/local/lib/python3.12/site-packages/channels/auth.py", line 185, in __call__
2024-10-14T00:10:37.622085327Z     return await super().__call__(scope, receive, send)
2024-10-14T00:10:37.622090527Z            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-10-14T00:10:37.622095527Z   File "/usr/local/lib/python3.12/site-packages/channels/middleware.py", line 24, in __call__
2024-10-14T00:10:37.622100927Z     return await self.inner(scope, receive, send)
2024-10-14T00:10:37.622105528Z            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-10-14T00:10:37.622109928Z   File "/usr/local/lib/python3.12/site-packages/channels/routing.py", line 132, in __call__
2024-10-14T00:10:37.622114728Z     return await application(
2024-10-14T00:10:37.622119828Z            ^^^^^^^^^^^^^^^^^^
2024-10-14T00:10:37.622125328Z   File "/usr/local/lib/python3.12/site-packages/channels/consumer.py", line 94, in app
2024-10-14T00:10:37.622130828Z     return await consumer(scope, receive, send)
2024-10-14T00:10:37.622135728Z            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2024-10-14T00:10:37.622140728Z   File "/usr/local/lib/python3.12/site-packages/channels/consumer.py", line 58, in __call__
2024-10-14T00:10:37.622146028Z     await await_many_dispatch(
2024-10-14T00:10:37.622151828Z   File "/usr/local/lib/python3.12/site-packages/channels/utils.py", line 57, in await_many_dispatch
2024-10-14T00:10:37.622157129Z     await task
2024-10-14T00:10:37.622161929Z   File "/usr/local/lib/python3.12/site-packages/channels/utils.py", line 49, in await_many_dispatch
2024-10-14T00:10:37.622167229Z     result = task.result()
2024-10-14T00:10:37.622172129Z              ^^^^^^^^^^^^^
2024-10-14T00:10:37.622177029Z RuntimeError: ASGI flow error
gi0baro commented 1 month ago

@Tragio @grant-oscillolabs it is quite hard for me to debug the almost cryptic stack traces of Django channels. It might be related to the OP or not; probably the best approach is to fix the original issue from the OP and let you check if that also covers your case. If not, then feel free to open a dedicated issue.