You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
"drain" event listener leak when unpiping to response #135
This is sort of a weird scenario, but this test case fails:
it('should clean up event listeners when res is unpiped to',function(done){varlistenerCountvarserver=createServer({threshold: 0},function(req,res){vartimes=0varint=setInterval(function(){varrs=fs.createReadStream('does not exist')rs.on('error',function(e){listenerCount=res.listenerCount('drain')rs.unpipe(res)})rs.pipe(res)if(times++>12){clearInterval(int)res.end('hello, world')}})})request(server).get('/').set('Accept-Encoding','gzip').expect(function(){assert.ok(listenerCount<2)}).expect(200,done)})
I hit this in some code that retries creating a read stream until the source exists. We clean up from our side: rs.on("error", e => { rs.unpipe("res"); }). Seems like compression needs to be cleaning up its listeners when "unpipe" happens.
there is also a leak caused by mapping ServerResponse.once to ServerResponse.on so there is no easy way to wait for 'drain' events to happen by just using the response.once('drain', ...)
changed the title [-]"drain" event listener leak when unpiping to response[/-][+]"drain" event listener leak when unpiping to response, using once("drain") or removeListener("drain")[/+]on Mar 7, 2019
changed the title [-]"drain" event listener leak when unpiping to response, using once("drain") or removeListener("drain")[/-][+]"drain" event listener leak when unpiping to response[/+]on Mar 7, 2019
If anyone came here looking for a workaround for the ability to call res.once('drain', ...) without have node warn about MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 drain listeners added to [Gzip]. Use emitter.setMaxListeners() to increase limit..
This is a bit of a mess, but you can do something like this:
letonDrain;// add a single drain listener early onres.on('drain',()=>{if(onDrain){// call the onDrain callback at most onceonDrain();onDrain=undefined;}});// later, when you would normally call res.once('drain', ...)onDrain=()=>{// resume your input stream or whatever};
I hope that helps someone feeling stuck on this old issue.
Activity
matthiasg commentedon Apr 17, 2018
there is also a leak caused by mapping ServerResponse.once to ServerResponse.on so there is no easy way to wait for 'drain' events to happen by just using the
response.once('drain', ...)[-]"drain" event listener leak[/-][+]"drain" event listener leak when unpiping to response[/+][-]"drain" event listener leak when unpiping to response[/-][+]"drain" event listener leak when unpiping to response, using once("drain") or removeListener("drain")[/+][-]"drain" event listener leak when unpiping to response, using once("drain") or removeListener("drain")[/-][+]"drain" event listener leak when unpiping to response[/+]support res.removeListener('drain'), res.once('drain')
support res.removeListener('drain'), res.once('drain')
support res.removeListener('drain'), res.once('drain')
support res.removeListener('drain'), res.once('drain')
support res.removeListener('drain'), res.once('drain')
support res.removeListener('drain'), res.once('drain')
support res.removeLister("drain"), res.once("drain")
support res.removeLister("drain"), res.once("drain")
support res.removeLister("drain"), res.once("drain")
support res.removeLister("drain"), res.once("drain")
support res.removeLister("drain"), res.once("drain")
support res.removeLister("drain"), res.once("drain")
support res.removeLister("drain"), res.once("drain")
support res.removeLister("drain"), res.once("drain")
support res.removeLister("drain"), res.once("drain")
jesseskinner commentedon Mar 7, 2022
If anyone came here looking for a workaround for the ability to call
res.once('drain', ...)without have node warn aboutMaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 drain listeners added to [Gzip]. Use emitter.setMaxListeners() to increase limit..This is a bit of a mess, but you can do something like this:
I hope that helps someone feeling stuck on this old issue.
support res.removeLister("drain"), res.once("drain")