ETIMEDOUT problems with node.js & amqp - javascript

I have 2 producers and two consumers in my project that uses rabbitmq via amqp module in node.js.
The code for establishing connection for consumers looks like this:
function init_consumers( ) {
console.log( 'mq: consumers connection established. Starting to init stuff..' );
global.queue.consumers.connection = con_c;
var fq_name = global.queue.fq_name;
var aq_name = global.queue.aq_name;
var q_opts = { durable:true };
var subscr_opt = { ack: true, prefetchCount: 1 };
var fq = con_c.queue( fq_name, q_opts, function() {
console.log( 'mq: consumer f queue prepared. ');
global.queue.consumers.fq = fq;
fq.subscribe( subscr_opt, function(msg) {
global.controllers.fc.ParseF( msg, function() { global.queue.consumers.fq.shift(); } );
});
});
var aq = con_c.queue( aq_name, q_opts, function() {
console.log( 'mq: consumer a queue prepared. ');
global.queue.consumers.aq = aq;
aq.subscribe( subscr_opt, function(msg) {
global.controllers.fc.ParseAndSaveToDB( msg, function() { global.queue.consumers.aq.shift(); } );
});
});
}
// connect and init
var con_c = amqp.createConnection( { url: global.queue.consumers.host }, global.queue.con_extra_options );
con_c.on( 'ready', init_consumers );
con_c.on( 'error', function(e) {
console.log( 'consumer error', e );
con_c.end();
if( typeof global.queue.consumers.connection !== 'undefined' ) { global.queue.consumers.connection.end(); }
});
Connection extra options are:
con_extra_options: { reconnect: true, // Enable reconnection
reconnectBackoffStrategy: 'linear',
reconnectBackoffTime: 5000, // Try reconnect 5 seconds
},
After project has launched in rabbitmq management console I clearly see that there is 1 connection established with 2 channels. Very good.
Then, it works just fine until an error (possible related to some disconnections) happens, giving me this output in console:
consumer error { [Error: read ETIMEDOUT] code: 'ETIMEDOUT', errno: 'ETIMEDOUT', syscall: 'read' }
The problem is that when this error happens, amqp tries to reconnect to queue server, but it seems that even with my code above the connection remains opened. In result after several hours of work I have 10 connections with like 50 channels opened, and the only thing remains for me is just to restart the project.
So, I have two questions:
Why this kind of error appears?
What modifications should I implement to stop the growth of connections and channels with time?

Add this to your url parameter
heartbeat=5
This will send heartbeat to AMQP server to let it know that your code is still alive
(You can set to something else except zero)

Related

Node.js - Get used memory of executed app (even after it has been killed)

How can I take memory usage of ChildProcess even after it was killed (in exec callback)?
I tried using the pidusage module, but it only works when the process is opened.
What I actually tried:
var proc = exec(execComm,(error, stdout, stderr) => {
if (error) {
callback({status: -1, reason:stderr });
}
var pidusage = require("pidusage");
pidusage(proc.pid,function(err,stat){
console.log(err,stat);
});
callback({ status:0, file: out });
});
But why does pidusage send [Error: No maching pid found]?
Is it because this module can't get info of the already closed one?
And how to get that info in the exec callback?
You could bind a helper to the exit signal of your app and read out memory usage then but since the gc will likely run on unpredictable times I'm not sure what use you get out of that.
const ExitHandler = () => { /* your code */ };
process.on( 'exit', ExitHandler.bind( null, { withoutSpace: false } ) ); // on closing
process.on( 'SIGINT', ExitHandler.bind( null, { withoutSpace: true } ) ); // on [ctrl] + [c]
process.on( 'uncaughtException', ExitHandler.bind( null, { withoutSpace: false } ) ); // on uncaught exceptions
I belive you could use something like node-heapdump to create heapdumps in your child-processes that you could inspect after the fact.
That way you could also have multiple dumps so you could inspect the memory usage over time.

How to implement effective two way communication with service worker and client web page

I want to implement effective 2 way communication between service worker and client web page.
here is my code
function twoWayMsg() {
if (navigator.serviceWorker.controller) {
var messageChannel = new MessageChannel();
messageChannel.port1.onmessage = function(event) {
console.log("Response the SW : ", event.data.message);
}
console.log("Sendingage to the service worker");
navigator.serviceWorker.controller.postMessage({
"command": "twoWayCommunication",
"message": "Hi, SW"
}, [messageChannel.port2]);
} else {
console.log("Nove ServiceWorker");
}
}
and
self.addEventListener('message', function(event) {
var data = event.data;
if (data.command == "twoWayCommunication") {
console.log("Respondingessage from the Page: ", data.message);
event.ports[0].postMessage({
"message": "Hi, Page"
});
}
});
is it good to create MessageChannel object each time?
if i use global variable for message channel object , then am getting this error
Failed to execute 'postMessage' on 'ServiceWorker': Port at index 0 is already neutered.
Error: Failed to execute 'postMessage' on 'ServiceWorker': Port at index 0 is already neutered.

error: Error: Stale RTM connection, closing RTM; rtm_close event not triggered

I have created a basic bot and left it connected. After some time, it gave the error Stale RTM connection, closing RTM. The rtm_close event was not fired and the process is still running then why did the bot stop listening.
How to deal with such issues in production? Why is rtm_close event not fired?
Environment:
Current version: "version": "0.5.4" (from botkit package.json)
OS: macOS Sierra (version: 10.12.4)
Simple code:
function rtmManager(controller, config) {
var bot = controller.spawn(config);
bot.startRTM(function(err, bot) {
if (err) {
debug('Failed to start RTM')
}
} );
controller.on('rtm_close', function(bot) {
debug('RTM connection is closed');
});
return bot;
}
var Botkit = require('botkit');
var bot_options = {
debug : process.env.DEBUG || false,
};
var controller = Botkit.slackbot(bot_options);
controller.startTicking();
rtmManager(controller, {token: process.env.SLACK_TOKEN});
In fact, rtm_close callback is invoked but it was throwing an error which is no where caught. So, it seems not called.

Is Karma server a singleton?

I am getting really weird behavior from the karma test runner, and I don't know why. As best as I can tell, the new Server() option isn't actually instanciating a new server, but is some how a singleton? I put the ? because that doesn't make sense to have a construnctor return a singleton... so confused.
"use strict";
var Server = require('karma').Server;
var runner = require('karma').runner;
var filePath = process.cwd();
filePath += "/karma.conf.js";
//files needs to be an array of string file matchers
function runTests(files, port) {
var config = {
configFile: filePath,
files: files,
port: port
};
var server = new Server(config, function(exitCode) {
console.log('Karma has server exited with ' + exitCode);
process.exit(exitCode)
});
server.on('run_complete', function (browser, result) {
console.log('A browser run was completed');
console.log(result);
});
server.on('browsers_ready', function () {
runner.run({port: port}, function(exitCode) {
console.log('Karma runner.run has exited with ' + exitCode);
process.exit(exitCode)
});
});
server.start();
}
runTests(['test/**/*Spec.js', 'tmp/example.js'], 9876);
runTests(['test/**/*Spec.js', 'tmp/example2.js'], 9877);
runTests(['test/**/*Spec.js', 'tmp/example3.js'], 9878);
The output I get is :
A browser run was completed
{ success: 1,
failed: 0,
error: false,
disconnected: false,
exitCode: 0 }
A browser run was completed
{ success: 0,
failed: 1,
error: true,
disconnected: false,
exitCode: 1 }
A browser run was completed
{ success: 0,
failed: 1,
error: true,
disconnected: false,
exitCode: 1 }
Karma runner.run has exited with 0
As you can see, the server never exits (why, i don't know), and the runner only exits once, why? I still can't say... The expected behavior was that three karma server instances would be created, and they would fire .on(browser_ready in no particular order. This in turn would cause the runner to tell the server at that port to run (3 separate times). Then, when the run is complete, it would exit the runner (3 times not once) printing the results to the terminal, and at some point exit the server (3 times not 0).

How to reconnect after you called .disconnect()

Question: How do you reconnect a client to the server after you have issued a manual .disconnect()?
In my current project, I need to disconnect a client from the server when the user log out from the session. I did a socket.disconnect() to do the disconnection successfully. Server removed the user from the session.
After awhile, the user decided to login again, but socket.io refuses to connect.
I am clear that Socket.IO has implemented reconnection algorithm but clearly this is a different case.
Below is the piece of code where I do the connection. On second trigger of this block of code, object socket was created, but no connect was fired from this object.
//Start the socket
var socket = io.connect(SOCKET_IO_URL);
socket.on('connect', function() {
me.fireEvent('connect');
socket.emit('register', {
hashed_identifier: hashed_identifier,
account_id: account_id
});
});
socket.on('ready', function() {
me.ready = true;
me.log('Handshake done. Listening for new data');
});
socket.on('data', function(data) {
me.fireEvent('data', data);
//Tells server we received it
socket.emit('data', {ack: 1});
});
socket.on('disconnect', function() {
me.fireEvent('disconnect');
});
UPDATE: As requested by #Tony
In fact the whole thing is wrapped under Sencha Touch 2.0, but I believe there is nothing to do with ST2.0
This is my Data Class. Usage of this class is when the user logged in, this class will get initialized. And upon the user logout, the system will call the disconnect() method in this class.
When the user login again, this class is initialized again, but funny is the socket somehow retained all the previous events and sessions it has previously.
/**
* Serve as interface to wait for data communication in between server and client
*/
Ext.define('go.module.connect.Data', {
mixins: {
observable: 'Ext.mixin.Observable'
},
config: {
account: null
},
ready: false,
socket: null,
constructor: function(cfg) {
var me = this,
hashed_identifier = Sha1.hash(go.__identifier);
me.initConfig(cfg);
var account_id = me.getAccount().get('id');
//Start the socket
var socket = io.connect(SOCKET_IO_URL);
socket.on('connect', function() {
console.log('connect');
me.fireEvent('connect');
socket.emit('register', {
hashed_identifier:hashed_identifier,
account_id: account_id
});
});
socket.on('ready', function() {
me.ready = true;
me.log('Handshake done. Listening for new data');
});
socket.on('data', function(data) {
me.fireEvent('data', data);
//Tells server we received it
socket.emit('data', {ack: 1});
});
socket.on('disconnect', function() {
me.fireEvent('disconnect');
});
console.log(socket);
if (!socket.socket.connected){
socket.socket.reconnect();
}
me.socket = socket;
me.callParent([cfg]);
},
disconnect: function() {
this.socket.disconnect();
this.socket.removeAllListeners();
this.socket.socket.removeAllListeners();
},
log: function(msg) {
console.log('## Connect: '+msg);
}
});
And below is my console.log results:
And below is my node.js debug window
I believe the root cause of this funny scenario is that the previously attached connect event listener is not removed thoroughly. How should I remove it? Should I use once? or I should specify the listener function as well. I thought removeAllListeners() is sufficient for this task.
The standard approach in latest socket.io is:
socket.on('disconnect', function() {
socket.socket.reconnect();
})
This is what I've been using in my app and works great. It also ensures that the socket keeps trying to reconnect if the server goes way, and eventually reconnects when the server is back online.
In your case, you need to ensure two things:
You create your socket only once. Don't call socket = io.connect(...) more than once.
You setup your event handling only once - otherwise they will be fired multiple times!
So when you want to reconnect the client, call socket.socket.reconnect(). You can also test this from the browser console in FireFox and Chrome.
You can reconnect by following client side config.
// for socket.io version 1.0
io.connect(SERVER_IP,{'forceNew':true };
I'm doing this way with socket.io 1.4.5 and it seems to work, for now:
var app = {
socket: null,
connect: function() {
// typical storing of reference to 'app' in this case
var self = this;
// reset the socket
// if it's not the first connect() call this will be triggered
// I hope this is enough to reset a socket
if( self.socket ) {
self.socket.disconnect();
delete self.socket;
self.socket = null;
}
// standard connectiong procedure
self.socket = io.connect( 'http://127.0.0.1:3000', { // adapt to your server
reconnection: true, // default setting at present
reconnectionDelay: 1000, // default setting at present
reconnectionDelayMax : 5000, // default setting at present
reconnectionAttempts: Infinity // default setting at present
} );
// just some debug output
self.socket.on( 'connect', function () {
console.log( 'connected to server' );
} );
// important, upon detection of disconnection,
// setup a reasonable timeout to reconnect
self.socket.on( 'disconnect', function () {
console.log( 'disconnected from server. trying to reconnect...' );
window.setTimeout( 'app.connect()', 5000 );
} );
}
} // var app
app.connect();
socket.socket.connect();
gets you reconnected.
It seems to me it is how you handle the disconnect...
Worked for me using socket.io - v1.1.0
wrong way...
var sock = io( '/' );
sock.on( 'connect', function(x) { console.log( 'Connected', x ); } );
// now we disconnect at some point:
sock.disconnect();
// now we try to reconnect...
sock.connect()
// or
sock.reconnect();
// - both seem to create the new connection in the debugger, all events are missing though
correct way...
// As above with 3 extra characters, everything functions as expected...
//events fire properly...
sock.io.disconnect();
// consequently i'm also using (for consitency)
sock.io.reconnect();
// sock.connect() still seems to work however.
socket.io v2.0 (current)
For the peoples that was looking as me for the last version please find the doc extract as below:
To manually reconnect:
socket.on('disconnect', () => {
socket.open();
});
socket.io-client v2.2.0
import io from "socket.io-client"
var socket = io(url) // initial connection
const reconnect = () => {
if(!socket.connected) {
socket = io(url) // reconnects to a new socket
}
}

Categories

Resources