-
Notifications
You must be signed in to change notification settings - Fork 39
Description
Hi guys,
I've been trying to test aiohttp-sse with the EventSource 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.
# 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:
# 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:
'{"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
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.
{"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!