Azure / Azure/fetch-event-source
Can't close `fetchEventSource` with `AbortController` in React
- Dominant language
- TypeScript
- Stars
- 2.9k
- Forks
- 196
- PR merge metrics
- No merged PRs in 30d
Description
Hello. I'm aware this topic has been raised many times here already, and I have read all of those issues with no success. Indeed, in most cases those issues have comments from people saying the proposed solution didn't work for them either. I am running my app in `React.StrictMode`, which causes each component to mount/unmount/remount to help identify unexpected side-effects and so on. In my case this is causing two `fetchEventSource` requests to be fired, which is expected. What's unexpected, is that using an `AbortController` does not close the first connection on unmount. This is my hook:
```javascript
const useStreamTradingNotifications = () => {
const [ abortController, setAbortController ] = useState(new AbortController());
useEffect(() => {
console.log("useEffect called");
const stream = async () => {
await fetchEventSource("http://127.0.0.1:8000/v1/notifications", {
signal: abortController.signal,
onmessage(msg) {
if (abortController.signal.aborted){
console.log("still getting messages from aborted signal")
}
console.log(`event: ${msg.event}`)
if (msg.event == "update") {
console.log(JSON.parse(msg.data))
}
},
});
};
stream();
return () => {
console.log("abort called")
abortController.abort();
setAbortController(new AbortController());
}
}, []);
};
```
When I run my app, I see the following logs:

As you can see:
1. `useEffect` is called twice, as the component is mounted/unmounted/remounted [expected]
2. `abortController.abort` is called when the first component unmounts [expected]
3. Subsequently I receive two of each message (the logs above are truncated, and just includes the first duplicate). For one of the two streams, I can confirm that the messages are being received on an already-aborted connection (`still getting messages from aborted signal`).
Furthermore, in my backend logs, when I close a browser window with an active connection I see a log like:
```
[2024-07-09T11:13:37.409247Z][sse_starlette.sse][DEBUG] Got event: http.disconnect. Stop streaming.
```
But I never see this message as the result of `AbortController.abort` being called. I have tried assigning a new instance of `AbortController` after abort (as suggested [here](https://github.com/Azure/fetch-event-source/issues/24#issuecomment-1691426586)), which had no affect. I have tried doing a similar thing with `setState` (as mentioned [here](https://github.com/Azure/fetch-event-source/issues/24#issuecomment-1762053484)) which made the problem much worse (kept creating connections until the browser crashed). I tried to use `useRef` to manage the controller (suggested [here](https://github.com/Azure/fetch-event-source/issues/24#issuecomment-1796842392), which also doesn't work.
The fact that I can see `abort` being called, but never see a `http.disconnect` on the backend, convinces me this must be a bug. But if anybody has a suspicion that I've screwed something up I'd really appreciate their suggestion.
Many thanks
Contributor guide
Assessment
This issue has not been assessed yet.