EventEmitter memory leak detected with node-rest-client - node.js

During the execution of my mocha testsuit, the following warning is reported by Node.js:
(node) warning: possible EventEmitter memory leak detected. 11 error listeners a
dded. Use emitter.setMaxListeners() to increase limit.
Trace
at Object.addListener (events.js:179:15)
at new exports.Client (C:\xyz\node_modules\node-rest-client\lib\node-rest-
client.js:320:17)
at Context.<anonymous> (C:\xyz\test\backend\rest\resources.js:40:10)
...
I strongly suspect this has to do with node-rest-client module, that I use. The last showed line, indicated in the warning, is actually:
rest = new Client();
If I execute only a single testcase which throws this warning, the warning does not shows up. It happens only when I execute the whole testsuite, with around 15 new Client() lines.
I have not found a way to somehow close the rest client, so I now tried simply with:
delete rest
It did not help to remove the warning.
Any clues?

This isn't necessarily a problem, more a warning of the system to make sure that you know what you're doing.
Because of the internals of node-rest-client you can't change it specifically for that module (see also this issue), but to get rid of the warning during your tests, put this somewhere at the top of your code:
require('events').EventEmitter.defaultMaxListeners = Infinity;
More information here.

Related

nodejs setMaxListeners to avoid memory leak detection

I read some other questions and posts, but I couldn't find where to apply .setMaxListeners(0).
I'm using a simple websocket-server which comes up with the errer:
(node) warning: possible EventEmitter memory leak detected. 11 listeners added. Use emitter.setMaxListeners() to increase limit.
Trace
at Socket.EventEmitter.addListener (events.js:160:15)
at Socket.Readable.on (_stream_readable.js:689:33)
at XHRPolling.Transport.setHandlers (D:\nodeJS\host\node_modules\socket.io\lib\transport.js:116:15)
at XHRPolling.HTTPPolling.setHandlers (D:\nodeJS\host\node_modules\socket.io\lib\transports\http-polling.js:53:39)
at XHRPolling.Transport.handleRequest (D:\nodeJS\host\node_modules\socket.io\lib\transport.js:70:10)
at XHRPolling.HTTPTransport.handleRequest (D:\nodeJS\host\node_modules\socket.io\lib\transports\http.js:84:39)
at XHRPolling.HTTPPolling.handleRequest (D:\nodeJS\host\node_modules\socket.io\lib\transports\http-polling.js:73:41)
at XHRPolling.Transport (D:\nodeJS\host\node_modules\socket.io\lib\transport.js:31:8)
at XHRPolling.HTTPTransport (D:\nodeJS\host\node_modules\socket.io\lib\transports\http.js:29:13)
at XHRPolling.HTTPPolling (D:\nodeJS\host\node_modules\socket.io\lib\transports\http-polling.js:27:17)
I'm instantiating the router this way:
var app = require('http').createServer(handler)
, io = require('socket.io').listen(app, { log: false })
, fs = require('fs');
app.listen(8070);
Then I'm listening for incomming socket-requests:
io.sockets.on('connection', function (socket) {
socket.on('createTake', function(data){...}
});
Where can I apply the MaxListeners?
I already tried this:
io.sockets.on(...).setMaxListeners(0);
But it doesn't work.
You are attaching listeners to io.sockets (io.sockets.on(...)). And you should apply setMaxListeners to the same object (to EventEmmiter). So try:
io.sockets.setMaxListeners(0);
This is regulated by "maxListeners" option. You have 2 ways: disable memory leak completely (i would not recommend doing this) or increase maxListeners.
1. To keep feature active, just not too aggressive:
Default value is 10, increase this value instead to keep memory leak detection active, but not so aggressive. Enter whatever number you need. I would start with little steps, if you don't know actually how many listeners you will be using. In error you got number how much listeners you attached at that moment.
io.sockets.setMaxListeners(15);
2. Disable memory leak feature completely:
io.sockets.setMaxListeners(0);
Other connected tips:
Get current value:
io.sockets.getMaxListeners();
If you need to react only once for event use io.sockets.once(...) it will remove unused listeners. tomekK

Infinite loop on net.js on simple NodeJS HTTP Proxy

I am making an handmade HTTP Proxy with NodeJS, but when there are many requests per seconds net.js is entering in an infinite loop while reading end of null connection. (it happens to random way around 40 req/s).
I separated the code that caused the bug creating a simple HTTP Proxy throwing the problem :
The code : https://gist.github.com/Ifnot/5336823
I put net.js to debug mode using command "NODE_DEBUG=net node main.js" and even when all connections seems to be closed the program output this indefinitely :
The debug : https://gist.github.com/Ifnot/5274181
NOTE : When the loop begin i can see this error :
(node) warning: possible EventEmitter memory leak detected. 11 listeners added. Use emitter.setMaxListeners() to increase limit.
Trace
at Socket.EventEmitter.addListener (events.js:160:15)
at Socket.Readable.on (_stream_readable.js:653:33)
at Socket.EventEmitter.once (events.js:179:8)
at TCP.onread (net.js:527:26)
Am I doing something wrong ? Anyone know what happens ? Why this problem appear ?
(I am using node v0.10.4, problem was seen in previous version v0.9.x)
It is a bug from nodejs core. We are talking about here :
https://github.com/joyent/node/issues/5108
Bug comes after version 0.8.23, so the solution is to download and compile the node version 0.8.23 :
http://blog.nodejs.org/2013/04/08/node-v0-8-23-legacy/

How to handle exceptions thrown in Isolates?

I'm experimenting with Dart and using the new streamSpawnFunction to create a new isolate.
I'm running my code in Dartium but i've noticed that if some kind of unrecoverable error occurs in the isolate i get no error message on the console. Because breakpoints in Isolate code are not working debugging is really painful.
The old Port based Isolate spawn function (spawnFunction) has a callback function for handling errors. I wonder why this is not available with streamSpawnFunction. Is there a new way to subscribe to the error events of an Isolate?
The missing functionality of streamSpawnFunction is just an oversight. I filed http://dartbug.com/9208 and I will try to fix it next week.
I'm not sure if it is a known problem that breakpoints don't work in isolates. I will let you file a bug-report (http://dartbug.com) so the devs can ask you questions and you are kept informed on the process.

possible EventEmitter memory leak detected

I am getting following warning:
(node) warning: possible EventEmitter memory leak detected. 11 listeners added. Use emitter.setMaxListeners() to increase limit.
Trace:
at EventEmitter.<anonymous> (events.js:139:15)
at EventEmitter.<anonymous> (node.js:385:29)
at Server.<anonymous> (server.js:20:17)
at Server.emit (events.js:70:17)
at HTTPParser.onIncoming (http.js:1514:12)
at HTTPParser.onHeadersComplete (http.js:102:31)
at Socket.ondata (http.js:1410:22)
at TCP.onread (net.js:354:27)
I wrote code like this in server.js:
http.createServer(
function (req, res) { ... }).listen(3013);
How to fix this ?
I'd like to point out here that that warning is there for a reason and there's a good chance the right fix is not increasing the limit but figuring out why you're adding so many listeners to the same event. Only increase the limit if you know why so many listeners are being added and are confident it's what you really want.
I found this page because I got this warning and in my case there was a bug in some code I was using that was turning the global object into an EventEmitter! I'd certainly advise against increasing the limit globally because you don't want these things to go unnoticed.
This is explained in the node eventEmitter documentation
What version of Node is this? What other code do you have? That isn't normal behavior.
In short, its: process.setMaxListeners(0);
Also see: node.js - request - How to “emitter.setMaxListeners()”?
The accepted answer provides the semantics on how to increase the limit, but as #voltrevo pointed out that warning is there for a reason and your code probably has a bug.
Consider the following buggy code:
//Assume Logger is a module that emits errors
var Logger = require('./Logger.js');
for (var i = 0; i < 11; i++) {
//BUG: This will cause the warning
//As the event listener is added in a loop
Logger.on('error', function (err) {
console.log('error writing log: ' + err)
});
Logger.writeLog('Hello');
}
Now observe the correct way of adding the listener:
//Good: event listener is not in a loop
Logger.on('error', function (err) {
console.log('error writing log: ' + err)
});
for (var i = 0; i < 11; i++) {
Logger.writeLog('Hello');
}
Search for similar issues in your code before changing the maxListeners (which is explained in other answers)
By default, a maximum of 10 listeners can be registered for any single event.
If it's your code, you can specify maxListeners via:
const emitter = new EventEmitter()
emitter.setMaxListeners(100)
// or 0 to turn off the limit
emitter.setMaxListeners(0)
But if it's not your code you can use the trick to increase the default limit globally:
require('events').EventEmitter.prototype._maxListeners = 100;
Of course you can turn off the limits but be careful:
// turn off limits by default (BE CAREFUL)
require('events').EventEmitter.prototype._maxListeners = 0;
BTW. The code should be at the very beginning of the app.
ADD: Since node 0.11 this code also works to change the default limit:
require('events').EventEmitter.defaultMaxListeners = 0
Replace .on() with once(). Using once() removes event listeners when the event is handled by the same function.
If this doesn't fix it, then reinstall restler with this in your package.json
"restler": "git://github.com/danwrong/restler.git#9d455ff14c57ddbe263dbbcd0289d76413bfe07d"
This has to do with restler 0.10 misbehaving with node. you can see the issue closed on git here: https://github.com/danwrong/restler/issues/112
However, npm has yet to update this, so that is why you have to refer to the git head.
Node Version : v11.10.1
Warning message from stack trace :
process.on('warning', e => console.warn(e.stack));
(node:17905) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 wakeup listeners added. Use emitter.setMaxListeners() to increase limit
MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 wakeup listeners added. Use emitter.setMaxListeners() to increase limit
at _addListener (events.js:255:17)
at Connection.addListener (events.js:271:10)
at Connection.Readable.on (_stream_readable.js:826:35)
at Connection.once (events.js:300:8)
at Connection._send (/var/www/html/fleet-node-api/node_modules/http2/lib/protocol/connection.js:355:10)
at processImmediate (timers.js:637:19)
at process.topLevelDomainCallback (domain.js:126:23)
After searching for github issues, documentation and creating similar event emitter memory leaks, this issue was observed due to node-apn module used for iOS push notification.
This resolved it :
You should only create one Provider per-process for each
certificate/key pair you have. You do not need to create a new
Provider for each notification. If you are only sending notifications
to one app then there is no need for more than one Provider.
If you are constantly creating Provider instances in your app, make
sure to call Provider.shutdown() when you are done with each provider
to release its resources and memory.
I was creating provider object each time the notification was sent and expected the gc to clear it.
I am getting this warning too when install aglio on my mac osx.
I use cmd fix it.
sudo npm install -g npm#next
https://github.com/npm/npm/issues/13806
I prefer to hunt down and fix problems instead of suppressing logs whenever possible. After a couple days of observing this issue in my app, I realized I was setting listeners on the req.socket in an Express middleware to catch socket io errors that kept popping up. At some point, I learned that that was not necessary, but I kept the listeners around anyway. I just removed them and the error you are experiencing went away. I verified it was the cause by running requests to my server with and without the following middleware:
socketEventsHandler(req, res, next) {
req.socket.on("error", function(err) {
console.error('------REQ ERROR')
console.error(err.stack)
});
res.socket.on("error", function(err) {
console.error('------RES ERROR')
console.error(err.stack)
});
next();
}
Removing that middleware stopped the warning you are seeing. I would look around your code and try to find anywhere you may be setting up listeners that you don't need.
In my case, it was child.stderr.pipe(process.stderr) which was being called when I was initiating 10 (or so) instances of the child. So anything, that leads to attach an event handler to the same EventEmitter Object in a LOOP, causes nodejs to throw this error.
Sometimes these warnings occur when it isn't something we've done, but something we've forgotten to do!
I encountered this warning when I installed the dotenv package with npm, but was interrupted before I got around to adding the require('dotenv').load() statement at the beginning of my app. When I returned to the project, I started getting the "Possible EventEmitter memory leak detected" warnings.
I assumed the problem was from something I had done, not something I had not done!
Once I discovered my oversight and added the require statement, the memory leak warning cleared.
Thanks to RLaaa for giving me an idea how to solve the real problem/root cause of the warning. Well in my case it was MySQL buggy code.
Providing you wrote a Promise with code inside like this:
pool.getConnection((err, conn) => {
if(err) reject(err)
const q = 'SELECT * from `a_table`'
conn.query(q, [], (err, rows) => {
conn.release()
if(err) reject(err)
// do something
})
conn.on('error', (err) => {
reject(err)
})
})
Notice there is a conn.on('error') listener in the code. That code literally adding listener over and over again depends on how many times you call the query.
Meanwhile if(err) reject(err) does the same thing.
So I removed the conn.on('error') listener and voila... solved!
Hope this helps you.
As pointed out by others, increasing the limit is not the best answer. I was facing the same issue, but in my code I was nowhere using any event listener. When I closely looked into the code, I was creating a lot of promises at times. Each promise had some code of scraping the provided URL (using some third-party library). If you are doing something like that, then it may be the cause.
Refer this thread on how to prevent that: What is the best way to limit concurrency when using ES6's Promise.all()?
i was having the same problem. and the problem was caused because i was listening to port 8080, on 2 listeners.
setMaxListeners() works fine, but i would not recommend it.
the correct way is to, check your code for extra listeners, remove the listener or change the port number on which you are listening, this fixed my problem.
I was having this till today when I start grunt watch. Finally solved by
watch: {
options: {
maxListeners: 99,
livereload: true
},
}
The annoying message is gone.
You need to clear all listeners before creating new ones using:
Client / Server
socket.removeAllListeners();
Assuming socket is your client socket / or created server socket.
You can also subscribe from specific event listeners like for example removing the connect listener like this:
this.socket.removeAllListeners("connect");
I was facing the same issue, but i have successfully handled with async await.
Please check if it helps.
let dataLength = 25;
Before:
for (let i = 0; i < dataLength; i++) {
sftp.get(remotePath, fs.createWriteStream(xyzProject/${data[i].name}));
}
After:
for (let i = 0; i < dataLength; i++) {
await sftp.get(remotePath, fs.createWriteStream(xyzProject/${data[i].name}));
}
In my case it was due to not closing the Sequelize connections to database while creating them inside of the async function called with setInterval.
You said you are using process.on('uncaughtException', callback);
Where are you executing this statement? Is it within the callback passed to http.createServer?If yes, different copy of the same callback will get attached to the uncaughtException event upon each new request, because the function (req, res) { ... } gets executed everytime a new request comes in and so will the statement process.on('uncaughtException', callback);Note that the process object is global to all your requests and adding listeners to its event everytime a new request comes in will not make any sense. You might not want such kind of behaviour. In case you want to attach a new listener for each new request, you should remove all previous listeners attached to the event as they no longer would be required using: process.removeAllListeners('uncaughtException');
Our team's fix for this was removing a registry path from our .npmrc. We had two path aliases in the rc file, and one was pointing to an Artifactory instance that had been deprecated.
The error had nothing to do with our App's actual code but everything to do with our development environment.
Adding EventEmitter.defaultMaxListeners = <MaxNumberOfClients> to node_modules\loopback-datasource-juggler\lib\datasource.js fixed may problem :)
Put this in the first line of your server.js (or whatever contains your main Node.js app):
require('events').EventEmitter.prototype._maxListeners = 0;
and the error goes away :)

global leak errors in mocha

I was trying to unit test the apple push notification library when I got a global leak error trying to open up an APN connection.
Is that a configuration error on my part or an error in node-apn or mocha?
I'm not sure I understand what checkGlobals is doing... is it just checking to see if any global variable are being set?
0) Feed "before all" hook:
Error: global leak detected: hasCert
at Runner.checkGlobals (/usr/lib/node_modules/mocha/lib/runner.js:96:21)
at Runner.<anonymous> (/usr/lib/node_modules/mocha/lib/runner.js:41:44)
at Runner.emit (events.js:64:17)
at /usr/lib/node_modules/mocha/lib/runner.js:159:12
at Hook.run (/usr/lib/node_modules/mocha/lib/runnable.js:114:5)
at next (/usr/lib/node_modules/mocha/lib/runner.js:157:10)
at Array.<anonymous> (/usr/lib/node_modules/mocha/lib/runner.js:165:5)
at EventEmitter._tickCallback (node.js:126:26)
Yes, Mocha features a global leak detection mechanism which alerts and fails if your code under test introduces global variables.
If hasCert is declared in a library and you have no control over its creation, you can tell Mocha to ignore it.
On the command line,
$ mocha --globals hasCert
To quote the documentation:
[This option] accepts a comma-delimited list of accepted global variable names. For example suppose your app deliberately exposes a global named app and YUI, you may want to add --globals app,YUI.
In a browser:
mocha.setup({globals: ['hasCert']});
You can also disable global leak detection by passing:
mocha --ignore-leaks
In a browser:
mocha.setup({ignoreLeaks: true});
I ran into this problem as well, you probably forgot a var statement somewhere like I did, which in JS means that a global variable will be created.
You may have to hunt it down yourself depending on how you structured your app, and hopefully it's not a 3rd-party bit of code that's causing this. :P
You should use JSLint or JSHint through your project, they should help uncover the source if it's anywhere in your code.
This can also happen if you forget new in a call to a constructor. In that case, this is the global object so any properties introduced in the constructor will be added to the global object.
That problem should not go undetected for long, but it's an interesting test failure.
I came across this answer when I trying to figure out how to squelch JSONP leaks such as:
Error: global leak detected: jQuery20305777117821853608_1388095882488
Squelch jQuery JSONP "leaks" via:
mocha.setup({
globals: ['jQuery*']
});
I was encountering this error for many functions as follows:
1) test "before all" hook:
Error: global leaks detected: __timers, _document, history, addEventListener, removeEventListener, dispatchEvent, raise, __stopAllTimers, Image, _virtualConsole, run, getGlobal, dispose, top, parent, self, frames, window, _frame, $, jQuery, Handlebars, Ember, Em, MetamorphENV, Cloud, jQuery1102048038746835663915, _listeners, _length, length, document, location, close, getComputedStyle, navigator, name, innerWidth, innerHeight, outerWidth, outerHeight, pageXOffset, pageYOffset, screenX, screenY, screenLeft, screenTop, scrollX, scrollY, scrollTop, scrollLeft, alert, blur, confirm, createPopup, focus, moveBy, moveTo, open, print, prompt, resizeBy, resizeTo, scroll, scrollBy, scrollTo, screen, mapper, mapDOMNodes, visitTree, markTreeReadonly, INDEX_SIZE_ERR, DOMSTRING_SIZE_ERR, HIERARCHY_REQUEST_ERR, WRONG_DOCUMENT_ERR, INVALID_CHARACTER_ERR, NO_DATA_ALLOWED_ERR, NO_MODIFICATION_ALLOWED_ERR, NOT_FOUND_ERR, NOT_SUPPORTED_ERR, INUSE_ATTRIBUTE_ERR, INVALID_STATE_ERR, SYNTAX_ERR, INVALID_MODIFICATION_ERR, NAMESPACE_ERR, INVALID_ACCESS_ERR, exceptionMessages, DOMException, NodeList, DOMImplementation, Node, NamedNodeMap, AttributeList, Element, DocumentFragment, Document, Attr, EventException, Event, UIEvent, MouseEvent, MutationEvent, EventTarget, languageProcessors, resourceLoader, HTMLCollection, HTMLOptionsCollection, HTMLDocument, HTMLElement, HTMLFormElement, HTMLLinkElement, HTMLMetaElement, HTMLHtmlElement, HTMLHeadElement, HTMLTitleElement, HTMLBaseElement, HTMLIsIndexElement, HTMLStyleElement, HTMLBodyElement, HTMLSelectElement, HTMLOptGroupElement, HTMLOptionElement, HTMLInputElement, HTMLTextAreaElement, HTMLButtonElement, HTMLLabelElement, HTMLFieldSetElement, HTMLLegendElement, HTMLUListElement, HTMLOListElement, HTMLDListElement, HTMLDirectoryElement, HTMLMenuElement, HTMLLIElement, HTMLCanvasElement, HTMLDivElement, HTMLParagraphElement, HTMLHeadingElement, HTMLQuoteElement, HTMLPreElement, HTMLBRElement, HTMLBaseFontElement, HTMLFontElement, HTMLHRElement, HTMLModElement, HTMLAnchorElement, HTMLImageElement, HTMLObjectElement, HTMLParamElement, HTMLAppletElement, HTMLMapElement, HTMLAreaElement, HTMLScriptElement, HTMLTableElement, HTMLTableCaptionElement, HTMLTableColElement, HTMLTableSectionElement, HTMLTableRowElement, HTMLTableCellElement, HTMLFrameSetElement, HTMLFrameElement, HTMLIFrameElement, StyleSheet, MediaList, CSSStyleSheet, CSSRule, CSSStyleRule, CSSMediaRule, CSSImportRule, CSSStyleDeclaration, StyleSheetList, VALIDATION_ERR, TYPE_MISMATCH_ERR, UserDataHandler, DOMError, DOMConfiguration, DOMStringList, XPathException, XPathExpression, XPathResult, XPathEvaluator, DocumentType, CharacterData, ProcessingInstruction, Comment, Text, NodeFilter, _parser, _parsingMode, _augmented
So I passed a wildcard in the setup function and it solved my issue.
mocha.setup({
globals: ['*']
});
I added "mocha.globals(['browserSync']);" below to fix my problem. The rest of the code is from https://mochajs.org/ - section : RUNNING MOCHA IN THE BROWSER
<script>mocha.setup('bdd')</script>
<script src="basic-spec.js"></script>
<script>
mocha.checkLeaks();
mocha.globals(['jQuery']);
mocha.globals(['___browserSync___']); //<<== This line was added
mocha.run();
</script>
Define Your stub variables before you use it.
var hasCert;
var hasCert = sinon.stub(instance, method);
Just for the record that ignoreLeaks option has been deprecated since Mocha 7.0.0;
We should use mocha.setup({ checkLeaks: false }) instead.

Resources