aio-libs / aio-libs/aiohttp-sse

SSE are batched

Aperta
#484 6 commenti 0 reazioni 0 assegnatari Vedi su GitHub
Lingua principale
Python
Stelle
238
Fork
37
Merge medio
2m
PR unite (30g)
1

Descrizione

Hi guys,

I've been trying to test aiohttp-sse with the [EventSource](https://www.dash-extensions.com/components/event_source) component in Dash. In a previous issue raised here, I failed to make it work since I forgot to include CORS handling. That is now solved, but I notice that the events arrive buffered to Dash. You can reproduce this with the following code.

```python
# server.py

from aiohttp import web
import json
import asyncio
from datetime import datetime
from aiohttp_sse import sse_response
import aiohttp_cors

app = web.Application()
routes = web.RouteTableDef()

cors = aiohttp_cors.setup(app, defaults={
"*": aiohttp_cors.ResourceOptions(
allow_credentials=True,
expose_headers="*",
allow_methods="*",
allow_headers="*",
max_age=3600
)
})

@routes.get("/hello")
async def hello(request: web.Request) -> web.StreamResponse:
async with sse_response(request) as resp:
while resp.is_connected():
services = json.dumps({
"time": f"Server Time : {datetime.now()}"
})
await resp.send(services)
await asyncio.sleep(1)
return resp

app.router.add_routes(routes)
for route in app.router.routes():
cors.add(route)

if __name__ == "__main__":
web.run_app(app, host='127.0.0.1', port=5000)
```

Now the Dash client:

```python
# client.py

from dash_extensions import EventSource
from dash_extensions.enrich import html, dcc, Output, Input, DashProxy
from dash.exceptions import PreventUpdate
import json

# Create small example app.
app = DashProxy(__name__)
app.layout = html.Div([
EventSource(id="sse", url="http://127.0.0.1:5000/hello"),
html.Span('SSE'),
html.Div(id="display")
])

@app.callback(
Output("display", "children"),
Input("sse", "message"),
)
def display(msg):
if msg is not None:
return msg
else:
raise PreventUpdate()

if __name__ == "__main__":
app.run_server(debug=True)
```

When I run these scripts, I get chucks like this in the `msg` variable in Dash:
```python
'{"time": "Server Time : 2024-04-05 09:44:52.022164"}\n{"time": "Server Time : 2024-04-05 09:44:53.023039"}\n{"time": "Server Time : 2024-04-05 09:44:54.023770"}\n{"time": "Server Time : 2024-04-05 09:44:55.025389"}\n{"time": "Server Time : 2024-04-05 09:44:56.027151"}\n{"time": "Server Time : 2024-04-05 09:44:57.029044"}\n{"time": "Server Time : 2024-04-05 09:44:58.030822"}\n{"time": "Server Time : 2024-04-05 09:44:59.032468"}\n{"time": "Server Time : 2024-04-05 09:45:00.033961"}\n{"time": "Server Time : 2024-04-05 09:45:01.035243"}\n{"time": "Server Time : 2024-04-05 09:45:02.036953"}\n{"time": "Server Time : 2024-04-05 09:45:03.038641"}\n{"time": "Server Time : 2024-04-05 09:45:04.040436"}\n{"time": "Server Time : 2024-04-05 09:45:05.041850"}\n{"time": "Server Time : 2024-04-05 09:45:06.043279"}'
```
Running the same thing in Starlette

```python
import asyncio
import json
from datetime import datetime
import uvicorn
from sse_starlette import EventSourceResponse
from starlette.applications import Starlette
from starlette.middleware import Middleware
from starlette.middleware.cors import CORSMiddleware

middleware = Middleware(CORSMiddleware, allow_origins=["*"], allow_headers=["*"])
server = Starlette(middleware=[middleware])

async def random_data():
while True:
await asyncio.sleep(1)
yield json.dumps({
"time": f"Server Time : {datetime.now()}"
})

@server.route("/hello")
async def sse(request):
generator = random_data()
return EventSourceResponse(generator)

if __name__ == "__main__":
uvicorn.run(server, port=5000)
```

gives atomic answers in the `msg` variable.
```python
{"time": "Server Time : 2024-04-05 11:04:50.266653"}
```

Note that, when I visit `http://127.0.0.1:5000/hello` after running the aiohttp-sse example, the events are received atomically, as expected.

So my question is, is there something in the transmission process that Starlette is doing and aiohttp-sse is omitting?

Please note that I would like to avoid the question of where is the bug (Dash EventSource or aiohttp-sse), since this easily leads to a kind of chicken-or-egg dilemma ... since their stuff works using the Starlette example. I'm just raising this here to see if you have any hint regarding this problem. I'm still resisting to switch to Starlette (or FastAPI) just because of this issue. Thanks in advance!

Guida per i contributori

Apri la guida per i contributori

Valutazione

Questa issue non è ancora stata valutata.

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.