I have a rather simple Node.JS application that uses subscribe to redis to receive messages which it then sends out to the connected clients. In addition I also use the subscribe method to pass Node.JS the command to send out emails to our users.
All works well but the memory usage grows daily until it reaches 1.1GB (using command top on linux) and then all further email sending fails with the error message:
{ [Error: spawn ENOMEM] code: 'ENOMEM', errno: 'ENOMEM', syscall: 'spawn' }
Where could that come from? The source code is rather simple:
Clients connecting:
io.sockets.on('connection', function (socket) {
nClients++;
console.log("Number of clients connected " + nClients);
socket.on('disconnect', function () {
nClients--;
console.log("Number of clients remaining " + nClients);
});
});
Receiving messages to send out to the clients
cli_sub.on("message",function(channel,message) {
if(nUseDelay==1) {
oo = JSON.parse(message);
ablv_last_message[oo[0]["base"]+"_"+oo[0]["alt"]] = message;
} else {
io.sockets.emit('ablv', message);
}
});
Sending out emails to clients
cli_email.on("message",function(channel,message) {
var transport = nodemailer.createTransport("sendmail");
oo = JSON.parse(message);
var mailOptions = {
from: email_sender,
bcc: oo["bcc"],
to: oo["recipient"],
subject: oo["subject"],
html: oo["text"]
}
try {
transport.sendMail(mailOptions);
} catch(err) {
console.log(err);
}
});
setInterval(function() {
Object.keys(ablv_last_message).forEach( function(key) {
io.sockets.emit('ablv', ablv_last_message[key]);
});
ask_last_message = [];
}, 5000);
When you call nodemailer.createTransport you're creating a pool of SMTP connections that's intended to be reused for the life of your application.
So change your code to call that once at your app's startup and then reuse the transport object each time you need to send an email.
Related
I am setting up a web socket server with socket.io and it seems like that messages are sent at least twice. Sometimes even trice. (very rarely even 4+ times) They are never sent once though. How should I setup my handlers or my client code so every message is received exactly once all the time?
My client is in swift and my server in node.js. I am running Ubuntu 16.04 on the server itself.
Node.js:
// Here is an array of all connections to the server
var connections = {};
io.sockets.on('connection', newConnection);
function newConnection(socket) {
socket.on('add-user', function(user) {
connections[user.id] = {
"socket": socket.id
};
});
socket.on('chat-message', function(message) {
console.log(message);
if (connections[message.receiver]) {
console.log("Send to: " + connections[message.receiver].socket);
// Here are some varients of the emit command. Seems like they all do the same
//io.sockets.connected[connections[message.receiver].socket].emit("chat-message", message);
//io.to(connections[message.receiver].socket).emit("chat-message", message);
socket.broadcast.to(connections[message.receiver].socket).emit("chat-message", message);
} else {
console.log("Send push notification")
}
});
//Removing the socket on disconnect
socket.on('disconnect', function() {
console.log("The client disconnected");
for (var id in connections) {
if (connections[id].socket === socket.id) {
delete connections[id];
}
}
})
}
The "console.log(message);" in the messages handler is only called once. That's the confusing part for me. If the handler is called twice, why is this only printed once? Still, on the handler in my swift code, the handler for received messages is called multiple times.
im using socket.io with sticky session (https://github.com/indutny/sticky-session). I have a little chat application and always when im using 2 or more sockets on one one machine the socket.on(...) event listener is firing very very slow. When i'm using only one socket-connection for each cluster everything works fine and fast. What could be the cause. Could it be because of sticky session?
Edit:
This is the socket- connect function (of my worker - clusters):
WebSockets.on('connect', function (socket) {
console.log(`${process.pid}`);
//send data example: socket.emit('news', {a: "b"});
//TODO: implement switch case that validates which chat type it is.
//TODO: why is the event so slow when using 2 connections?: https://socketio.slack.com/messages/C02AS4S1H/
socket.on('chat message', function (msg) {
console.log("sending message: " + msg)
try {
//send the message to all other cluster-workers:
process.send({ chat_message: msg });
} catch (e) { }
});
//if the cluster gets a message then he sends it to the user, if its the correct user
function message_handler(msg) {
try {
//TODO: send message only to the correct users
if (msg != null && msg.chat_message != null) {
WebSockets.emit('chat message', msg.chat_message);
}
} catch (e) { }
}
process.on('message', message_handler);
//When the socket disconnects:
socket.on('disconnect', function(reason) {
//remove the event listener:
process.removeListener('message', message_handler);
});
});
Explanation: I'm sending all the data i get from the socket to all the other clusters. Then I catch them with:
process.on('message', message_handler);
To send incomming chat messages.
I created the Clusters with sticky session like in the example (https://github.com/indutny/sticky-session)
I tried client 1 and client 2 program I can able to easily communicate with them. I can easily send the messages and receive the messages with them, but I don't know if one client is disconnected, how can I send the disconnected message to subscribed clients.
client 1:
var mqtt=require("mqtt");
var express=require("express");
var app=express();
var options={
keepalive:100,
port: 1883,
clientId:'1',
clientSession:false,
host: "http://localhost:8000",
will:
{
topic:'willMag',
payload:"connection closed abnormallly r",
qos:1,
retain:true
}
};
var client=mqtt.connect("tcp://192.168.43.137:1883",options);
client.on("connect",function()
{
setInterval(function()
{
client.publish("ranjith/princy","hello love you princy",function()
{
console.log("message published in client1");
});
},2000);
client.subscribe("bv/nivi");
client.on("message",function(topic,message)
{
console.log("I recieved the topic:"+topic);
console.log("I recieved the message:"+message);
});
});
client.on("disconnect",function()
{
console.log("disconnected client1");
});
app.listen(8000,function()
{
console.log("server listen at port 8000");
});
client 2:
var mqtt=require("mqtt");
var express=require("express");
var app=express();
var options={
keepalive:100,
port: 1883,
clientId:'2',
clientSession:false,
host: "http://localhost:8086",
will:
{
topic:'willMag',
payload:"connection closed abnormallly b",
qos:1,
retain:true
}
};
var client=mqtt.connect("tcp://192.168.43.137:1883",options);
client.on("connect",function()
{
setInterval(function(){
client.publish("bv/nivi","hello love you nivi",function()
{
console.log("message published in client2");
});
},2000);
client.subscribe("ranjith/princy");
client.on("message",function(topic,message)
{
console.log("I recieved the topic:"+topic);
console.log("I recieved the message:"+message);
});
});
client.on("disconnect",function()
{
console.log("disconnected client2");
});
app.listen(8086,function()
{
console.log("server listen at port 8000");
});
It's not totally clear what you are asking here, but:
With MQTT you can not know what clients are subscribed to what topics
There is no way to know if a message has been delivered to a specific client
You can build a system to determine if a client is probably online. You need to make use of the Last Will and Testament (LWT) feature.
When your client connects it publishes a retained message to a given topic (e.g. client1/online payload: 1)
You set the LWT to publish payload 0 to the same topic if the client goes off line due to a crash/network failure
When you shut the client down cleanly you need to publish a 0 to the topic manually as the LWT will only fire if there is a failure.
I am very new to nodejs. I need to send a message to rabbitMQ using common-mq module. I have installed this package by using the below command
npm install common-mq
I am not able to write the sender and receiver using this. Can anyone please help me in writing the sender and receiver using nodejs?
var commonmq = require('common-mq');
var connect = commonmq.connect('amqp://localhost:5672/queue');
How do I proceed after this?
sender.js looks like below
var commonmq = require("common-mq");
var queue = commonmq.connect('amqp://localhost:5672/queue', { implOptions: { defaultExchangeName: '' }});
var msg =JSON.stringify("Hello world");
console.log("going for ready");
queue.on('ready',function () {
console.log("inside event");
setTimeout(function() { queue.publish({ task: 'take out trash' }); }, 1000);
});
//queue.publish({ task: 'sweep floor' });
queue.on('error',function(err){
console.log("error is:"+err);
});
The receiver code goes like this
var commonmq = require("common-mq");
var queue = commonmq.connect('amqp://localhost:5672/queue', { implOptions: { defaultExchangeName: '' }
});
queue.on('message', function(message) {
console.log('Got a new message', message);
});
queue.on('error',function(e){
console.log("errrorrr ",e);
});
No messages are received. Please suggest me where am I messing up the things?
After you setup the service, you can listen for new messages or send new ones.
Receiver:
The receiver listens on a queue and performs actions based on the messages:
//setup the service
var queue = commonmq.connect('amqp://localhost:5672/queue');
queue.on('message', function(message) {
console.log('Got a new message', message);
//do something
});
//listen eventually on other events (error, ready)
Sender:
The sender publishes new messages. Even a receiver could do it...
//setup the service
var queue = commonmq.connect('amqp://localhost:5672/queue');
queue.publish(yourMessageAsObject);
There are a few other events you could listen to (for example in case of errors). Just check the manual on the npm site.
I'm making an application for our website where users can send chat messages with each other. I've managed to do this successfully using nodejs and socketio. I have a header with some sort of notification icon just like facebook that can be seen in all the pages. Now if the user opens multiple tabs and he receives a message, then all open tabs should see the icon light up. I've gotten this to work by tracking the socket connections opened by users through a 2D array of sockets:
var container = {};
io.sockets.on( 'connection', function(client) {
client.on('set account online', function(username) {
if (!(username in container)) {
console.log(username + " is now Online" );
container[username] = [];
}
client.username = username;
container[username].push(client);
});
client.on('set account offline', function(username) {
if (username in container) {
delete container[username];
console.log(username + " is now Offline" );
}
});
And then when a message is sent I iterate through the appropriate array element
client.on('send message', function(data) {
if (data.recipient in container) {
var clients = container[data.recipient];
for(var i = 0; i < clients.length;i++){
clients[i].emit('send message', {recipient: data.recipient, message: data.message });
}
}
});
That's working well and all (not sure how well coded it is though). The problem is if the user closes a tab, the socket for that tab still exists in the container variable and node would still try to emit to that socket if a message is received for that particular user. Also it just feels cleaner to un-track any disconnected socket.
I've been thinking about this and I think I have to tie the socket disconnect event to the client side's onbeforeunload event and we all know how that performs across different browsers. Any suggestion regarding what's the proper way to splice off disconnected sockets from the container array?
As per my comment:
You should really be implementing rooms. On each connection each user
should join their own room, any additional connections from the same
user should join this room. You can then emit data to the room and
each client inside it will receive the data.
Your code can be changed to:
io.sockets.on('connection', function(client) {
client.on('set account online', function(username) {
client.join(username);
});
client.on('set account offline', function(username) {
client.leave(username);
});
client.on('send message', function(data) {
io.to(data.recipient).emit('send message', {
recipient: data.recipient,
message: data.message
});
});
});