What causes the Node.js EventEmitter warnings? - javascript

My node.js backend has a lot of mongoose.connection.useDb lines because it frequently needs to switch databases. Today I restarted my server and got this warnings:
MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 connected listeners added to [NativeConnection].
It took me some time to find a solution, and I found that by just adding mongoose.connection.removeAllListeners() the warning dissapears. What does this mean, and what exactly is an event? It feels like if I remove all listeners that the code that used those databases (like when I needed to create a model for a schema) shouldn't work anymore, but that isn't the case.

What does this mean?
This warning indicates that you're registering 11 or more listeners for the same event or calling some code that is internally causing this to happen. The warning is because normal usage of an event emitter rarely needs 11 listeners for the same event.
Instead, this many listeners for the same event is usually an indication that you're registering for the same event over and over or repeatedly calling some function that causes the same listener over and over again. In your specific case it looks like you should perhaps use the noListener: true option when calling .useDb(). See the doc here and this troubleshooting report.
Failing to remove listeners that you are no longer using can create a regularly growing memory leak (just like the error message indicates) because nodejs can't tell that you no longer intend to use that listener. It's still registered for the event, the event can still occur and thus the listener (the ones you no longer intend to use) are still active. This takes additional memory inside the eventEmitter object and (perhaps more importantly), it may keep certain closure variables from getting garbage collected inside the listener callback function/scope.
So, whenever an eventEmitter object gets the 11th or more listener for the same event, it issues this warning.
If you show the actual code and context where this warning occurs, we could give you more specific advice about what you should/should not be doing in that code. The above is a generic description/advice because you didn't show your specific code and context.
What is an event?
This warning comes from an eventEmitter object which, given your explanation, is probably being used inside the database whenever you call .useDb(). Something you are doing with the database is causing it to register a listener for an event on an eventEmitter object. If you want to know more about events in the context of an eventEmitter object, I'd suggest reading the eventEmitter documentation.
In a nutshell, an eventEmitter object allows one to listen for events by calling obj.addListener("someEventName", fn) or the identical (but shorter) obj.on("someEventName, fn) where obj is an instance of the EventEmitter class. Then, other code can trigger events obj.emit("someEventName", someData). When an event is triggered, all registered listeners for that specific event name will have their callback called. Nodejs uses event objects and listeners like this in lots of places in its libraries. For example streams use listeners to listener for incoming data as in stream.on('data', myCallback).

Related

Publish/Subscribe with CustomEvents in JavaScript

I've got the task to talk about event based communicatoin and the publish/subscribe based communication in JavaScript.
After thinking about it I wonder that the CustomEvents in JavaScript actually use the publish/subscribe pattern.
Dispatching a CustomEvent is like publishing new data or triggering the update function in the subscribers and creating an event listener is the same es subscribing to a publisher.
In other words every time a event is thrown every listener's callback is run is just the same as every time a publisher publishes new data, the subscriber's update functions are called.
Is this a correct solution or did I not got the key concepts fo the two patterns?

(Angular) with many subscribers

What happens when you have too many subscribers? I have a directive that watches every route events, and I placed my directive inside of a NgFor.
I am just new to RxJS and I'm very concerned about the performance.
Performance Notes:
Event Loop:
All subscribing methods or functions are called as soon as an event fires, but not directly. They are handled by the Event Loop, and it can handle a lot of events firing at once.
I/O bound vs CPU bound functions:
But if the functions being called are not I/O bound, i.e. simple input output stuff, like logging, or calling Google Analytics, then performance will dip.
Imagine running Path Finding algorithm (A*, Dijsktra) on each event fired!
Unsubscribe as a best practice:
Another thing to keep in mind is to unsubscribe the event, in NgOnDestroy(), of the directive, it'll keep the potentially growing amount of events from spiraling out of control!

Should we consider the addEvenetListener method a loop?

As far as I understand, the addEvenetListener method will usually just listen to a certain event and when that event is triggered a callback function will be called to perform everything in the event handler code in that callback function.
addEventListener listens for each triggering of a certain event. To me it seems quite like a for each loop as initiated by the forEach() method.
I assume we could at least say both forEach() and addEvenetListener are loopish functions, though just functions (methods).
Javascript addEventListener follows the famous "don't call us, we will call you." Also known as the Hollywood principle.
In software engineering it's also called the observer or subscriber part as in the publisher/observer design pattern.
Basically when you call addEventListener for let's say the click event with a callback. It's going to call the core of JavaScript engine saying
"Hey I have a function that wants to be called everytime there is a click."
The JavaScript engine is going to store a reference to the callback. And then during the JavaScript event loop, everytime there is a click event, it's simply going to call all its references to callback.
So the loop is indeed happening inside the JavaScript event loop (which you have little control over). But your callback is a simple function that subscribed to a specific event and will be called at the right time to react to this event. There is no magic behind it.
In fact, your callback is not really listening for event, it just subscribes itself once to a specific event and then it's done. It might be called in the future, but it's surely not actively listening for it.
As far as I understand, in relation to the common JavaScript literature in 2017 (MDN), we shouldn't say it's a loop, because it's not one of the loops defined in JavaScript like for and while. We can indeed say it's an observer as it observers for each triggering of its associated event.
We don't iterate for each item in a collection, we observe for each triggering of the relevant event; One can say that the "for each" like behavior indicates "loopishness" and I personally find no flaw with that.

Backbone.Radio: what's the advantage of commands and requests over events

It seems like Backbone.Radio provides 2 new abstractions - commands and requests. They're pretty much identical to Backbone.Events, except that they can have only 1 subscriber. Is that it, and if so what advantage do they provide over events?
I plan on using Backbone.Events/Radio with React.js, if that helps.
I have not actually used Backbone.Radio but do make extensive use of Backbone.wreqr https://github.com/marionettejs/backbone.wreqr which provides an almost identical command service.
In my usage the difference between events and commands is:
For events to work the sender and receiver of an event must both exist and have a reference to each other and the receiver must be in a position to deal with the event properly. This can often be problematic in a fully asynchronous browser environment where different parts of your application are running at the same time.
Commands allow you to decouple the sender and receiver. One object, lets say a View A, can simply send command 'update_user_details'.
My second Object View B sets up a command handler for 'update_user_details' which will change the user details on the screen.
But what if View B does not yet exist, or is not yet rendered. In the event listener pattern you would have to make sure View A exists, that it passes a reference to itself to View B and then you attach an event listener in View B.
With commands it is not a problem, View A sends a command, if no-one has set a handler then nothing bad happens, the command just does nothing.
When View B turns up, totally independent of View A, it sets a handler and will respond to all future commands.
Just a final note about intent:
The event pattern can be thought about in this way: I, View A have just done something, anyone that is interested (the event listeners) can do what they like about it, I View A don't care what you do.
In the command pattern: I View A want someone to do something, I don't care who does it, I just want it done right.
Channels. The key difference with Backbone.Radio over plain vanilla Backbone.Events that I have seen is that it allows you to setup channels to which your code can 'tune in' e.g. from the documentation:
var userChannel = Backbone.Radio.channel('user');
This means that logical functions or apps in your code can emit and handle events only on a specific channel - even if you emit events with the same name, if they're on different channels you won't get cross-contamination. This ties in nicely with the principles behind separation of duties in your code.
The other other difference, and IMHO it's subtle, more to do with elegance of coding than any real functionality difference, is that if you're telling something to respond to an event then it's really a Command, and Backbone.Radio allows you to separate these kinds of event into that type. Similar logic applies to the Requests type.
For completeness...
The docs also explain that a Channel is an object that has all three types of messages (Events, Commands and Requests) mixed in. You mix it into an object (I use Marionette so I'm mixing into an instance of Marionette.Object) using Underscore/Lo-Dash's .extend():
_.extend(objectToBeExtended, Backbone.Radio.Requests);
And the same for Commands of course. The syntax for events is different as that's baked into Backbone itself so the second parameter is just Backbone.Events.

I think I have a memory leak in Event Emitter, how should I be cleaning up global variables?

I've noticed some odd activity in my MongoDB collection and I believe that some events I've received back to back are sharing global variables.
For instance, I had a document that I removed prematurely from the collection, then I received an event that referenced this document. What seems to have happened is the id from the previous event was used for this removed event. So the event caused my code to store data in the document that was previously called.
My question is, how should I be cleaning up global variables after each event? It seems difficult to pinpoint how this could even be done since all of the event calls are being done async and the end event is called before I'm done using the global variables. Sometimes I might even have many events that come in before the others are completed.
Do I have to go back to using only local variables? (ones stored using var variable_name = data;)?

Categories

Resources