generator stays active after calling EventSource.close() and closing the browser
wwitzel3 opened this issue · 2 comments
Hi, I think I am misunderstanding something or doing something wrong, but I am completely stuck on using this package due to event generators never stopping when the connection originates from an EventSource
creation in the browser. I've tried my best to capture what I'm experiencing below. I really appreciate any help or guidance.
I have a very simple test setup using basic JavaScript creating an EventSource
and a setTimeout that closes it 5 seconds later. I have a simple event generator that is sending a message every second.
When I test this with cURL, everything works as expected.
When I use the browser, the generator continues to run even after calling close()
and closing the browser completely.
Here is the stream handler in Python
def new_messages():
# Add logic here to check for new messages
yield "Hello World"
async def event_generator():
while True:
print("stream")
# If client closes connection, stop sending events
disconnected = await request.is_disconnected()
if disconnected:
break
# Checks for new messages and return them to client if any
if new_messages():
yield {
"event": "new_message",
"id": "message_id",
"retry": RETRY_TIMEOUT,
"data": "message_content",
}
await asyncio.sleep(STREAM_DELAY)
return EventSourceResponse(event_generator())
Here is the JavaScript
console.log("Creating eventSource");
this.eventSource = new EventSource(endpoint);
this.eventSource.addEventListener(
"message",
(ev): any => {
console.log(ev);
}
);
setTimeout(() => {
console.log("Calling eventSource.close()");
this.eventSource.close();
}, 5000);
Using cURL I can call this endpoint and when I Ctrl-C, I see the disconnect as expected.
Using a very simple JavaScript client in Chrome, after calling close
OR closing the browser completely, the generator task stays active.
After Ctrl-C on the uvicorn server, you can see all the tasks shutting down.
^CINFO: Shutting down
INFO: Waiting for connections to close. (CTRL+C to force quit)
cancelled
TRACE: 127.0.0.1:37810 - ASGI [5] Send {'type': 'http.response.body', 'body': '<0 bytes>', 'more_body': False}
TRACE: 127.0.0.1:37810 - HTTP connection lost
TRACE: 127.0.0.1:37810 - ASGI [5] Completed
cancelled
TRACE: 127.0.0.1:37804 - ASGI [3] Send {'type': 'http.response.body', 'body': '<0 bytes>', 'more_body': False}
TRACE: 127.0.0.1:37804 - HTTP connection lost
TRACE: 127.0.0.1:37804 - ASGI [3] Completed
cancelled
TRACE: 127.0.0.1:37860 - ASGI [7] Send {'type': 'http.response.body', 'body': '<0 bytes>', 'more_body': False}
TRACE: 127.0.0.1:37860 - HTTP connection lost
TRACE: 127.0.0.1:37860 - ASGI [7] Completed
INFO: Waiting for application shutdown.
TRACE: ASGI [1] Receive {'type': 'lifespan.shutdown'}
TRACE: ASGI [1] Send {'type': 'lifespan.shutdown.complete'}
TRACE: ASGI [1] Completed
INFO: Application shutdown complete.
INFO: Finished server process [9310]
INFO: Stopping reloader process [9299]
I was working on making a reproducer repo and was unable to reproduce using python -m http.server
. This got me digging in to things a bit more and it turns out the Vite proxy was holding the connection open. I wasn't able to get the Vite configuration to work correctly, so I added an .env.local
for CORS origins so I could bypass the Vite proxy completely.