nest: Possible memory leak when using server side events

Is there an existing issue for this?

  • I have searched the existing issues

Current behavior

I use Server-Sent Events for one of my routes and then push db changes for subscribed users. The functionality works fine, but as soon as the event count is 10k for example, the error appears:

(node:43243) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 101 drain listeners added to [SseStream]. Use emitter.setMaxListeners() to increase limit

Minimum reproduction code

https://gist.github.com/ggagosh/0850fd0100f17e2bc040095a917c0342

Steps to reproduce

No response

Expected behavior

I suppose should work without any warning

Package

Other package

No response

NestJS version

^9.0.0

Packages versions

"@nestjs/common": "^9.0.0",
"@nestjs/config": "2.3.1",
"@nestjs/core": "^9.0.0",
"@nestjs/event-emitter": "^1.4.1",
"@nestjs/graphql": "^11.0.5",
"@nestjs/jwt": "10.0.3",
"@nestjs/mongoose": "^9.2.2",
"@nestjs/passport": "9.0.3",
"@nestjs/platform-express": "^9.0.0",
"@nestjs/swagger": "6.3.0",
"@nestjs/terminus": "^9.2.2",

Node.js version

18.16.0

In which operating systems have you tested?

  • macOS
  • Windows
  • Linux

Other

No response

About this issue

  • Original URL
  • State: open
  • Created a year ago
  • Reactions: 2
  • Comments: 21 (6 by maintainers)

Commits related to this issue

Most upvoted comments

I have the same issue: (node:167175) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 drain listeners added to [SseStream]. Use emitter.setMaxListeners() to increase limit

I have the same issue, has anyone found some workaround/solution to this problem? In my case, I can reproduce the issue by sending HTTP requests and immediately cancelling them, after a couple of cancelled requests the warning pops up.

I have the same issue: (node:167175) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 drain listeners added to [SseStream]. Use emitter.setMaxListeners() to increase limit

Seems like some sort of issue with usd adding this.once('drain') here. Interestingly it doesn’t happen when using rxjs directly via interval

Stack Trace
(node:1588817) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 drain listeners added to [SseStream]. Use emitter.setMaxListeners() to increase limit
    at _addListener (node:events:587:17)
    at SseStream.addListener (node:events:605:10)
    at SseStream.Readable.on (node:internal/streams/readable:875:35)
    at SseStream.once (node:events:649:8)
    at SseStream.writeMessage (/home/jay/Documents/code/help/sse/node_modules/.pnpm/@nestjs+core@9.0.0_@nestjs+common@9.0.0_@nestjs+platform-express@9.0.0_reflect-metadata@0.1.13_rxjs@7.2.0/node_modules/@nestjs/core/router/sse-stream.js:70:18)
    at /home/jay/Documents/code/help/sse/node_modules/.pnpm/@nestjs+core@9.0.0_@nestjs+common@9.0.0_@nestjs+platform-express@9.0.0_reflect-metadata@0.1.13_rxjs@7.2.0/node_modules/@nestjs/core/router/router-response-controller.js:65:80
    at new Promise (<anonymous>)
    at /home/jay/Documents/code/help/sse/node_modules/.pnpm/@nestjs+core@9.0.0_@nestjs+common@9.0.0_@nestjs+platform-express@9.0.0_reflect-metadata@0.1.13_rxjs@7.2.0/node_modules/@nestjs/core/router/router-response-controller.js:65:50
    at /home/jay/Documents/code/help/sse/node_modules/.pnpm/rxjs@7.2.0/node_modules/rxjs/src/internal/operators/debounce.ts:101:21

I was able to fix my issue by completing the observable when the request socket is closed.

import {Request} from 'express';


@Sse()
see(@Req() req: Request): Observable<any> {
   return new Observable((subscriber) => {
      req.socket.on('close', () => {
          subscriber.complete();
      });
     // do your stream work here
   });
}

FYI: req.on('close') didn’t work for me. Had to use req.socket.on('close') instead.

You can use an AbortController and signal it to tell your other code to stop emitting events.

@ggagosh could you please provide an example with interval?

Hey, this is the example branch

I take the interval example from NestJS documentation, I just change the interval time to 0, because first I think the warning was caused by the amount of data I try to return.

In my case, I can reproduce this by aborting the client connection. Basically, start a SSE stream on the browser and then hit F5 to reload the webpage. This makes the browser disconnect and then the server will show this error.

@lxmfly123 I (like in the repro) use Subject from rxjs, which doesn’t seem to have anything resembling a .destroy() message. Any idea how to update it for the rxjs case?

I call subject.complete()

then I don’t think that that code is enough to reproduce your issue, right? Please share the full code along with the steps to reproduce.

why reproductions are required

example nest application you can use to reproduce this behavior. after running the application, use Postman or any other similar application and enter localhost:3000/sse, then check the console where the warning appears.

then I don’t think that that code is enough to reproduce your issue, right? Please share the full code along with the steps to reproduce.

why reproductions are required