Connection Pool for NodeJS - javascript

I have an app that has been maxing out the number of connection to MongoDB and I was under the assumption that if the drivers were set up correctly you didn't need to worry about closing connections.
I've seen people mention the Generic Pool module but what is the best process for closing or pooling connections using Node & MongoDB?
Here is my connection code for the app:
var sys = require("sys");
var app = require('http').createServer(handler);
var io = require('socket.io').listen(app);
app.listen(1337);
io.configure(function () {
io.set('authorization', function (handshakeData, callback) {
callback(null, true);
});
});
function handler (req, res, data) {
sys.puts('request made to trackerapp.js');
res.writeHead(200);
res.end(data);
}
io.sockets.on('connection', function (socket) {
socket.on('adTracker', function (data) {
var adRequestData = data;
var databaseUrl = "mongodb://dbuser:dbpass#mongolab.com/tracker";
var collections = ["cmnads"]
var db = require("mongojs").connect(databaseUrl, collections);
db.cmnads.insert({adRequest : adRequestData},function(err, updated) {
if( err || !updated ) console.log("mongo not updated" + err);
else console.log("data stored");
});
});
});

After seeing JohnnyHK's comment I was able to pull the connection event out of the Socket.io connection and it worked fine, see the solution below:
var databaseUrl = "mongodb://dbuser:dbpass#mongolab.com/tracker";
var collections = ["cmnads"];
var db = mongojs.connect(databaseUrl, collections);
io.sockets.on('connection', function (socket) {
socket.on('adTracker', function (data) {
var adRequestData = data;
//vars for MongoDB used to be created here... so new connect function was called on every request to socket.io
db.cmnads.insert({adRequest : adRequestData},function(err, updated) {
if( err || !updated ) console.log("mongo not updated" + err);
else console.log("data stored");
});
});
});

A technique I used with my express apps that seems have some measure of success is to open a connection to a mongo instance (thereby getting a connection pool) then sharing that db (that is now in the "connected" state) instance wherever it is needed. Something like this:
server = new Server(app.settings.dbsettings.host, app.settings.dbsettings.port, {auto_reconnect: true, poolSize: 5})
db = new Db(app.settings.dbsettings.db, server, {native_parser:false})
db.open(function(err, db) {
app.db = db;
server = app.listen(app.settings.port);
console.log("Express server listening on port %d in %s mode", app.settings.port, app.settings.env);
require('./apps/socket-io')(app, server);
});
This connects to the database at the highest level in my app before the program moves into the wait listen state.
Before I used this pattern I would create a new database object whenever I needed to interact with the database. The problem I found is that the new database object would create a new thread pool, consuming a bunch of ports. These were never cleaned up properly. After a period of time the machine that hosted the app would run out of ports!
Anyway, a variation on the code I have shown should be where you should do your thinking I believe.

Related

Express-generator, Socket.io Event issuing multiple times

I have create a node app using express generator. I have integrated socket.io in the application. Since express generator has their own way of creating express server i have followed this procedure to successfully integrate the Socket connection with listening server and made the io available throughout the application via res.io instance.
FILE: bin/www
#!/usr/bin/env node
var app = require('../app').app;
var debug = require('debug')('www:server');
var http = require('http');
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
/**
* Create HTTP server.
*/
var server = require('../app').server;
/app.js
//Express handler
var app = express();
// Socket configuration
var server = require('http').Server(app);
var io = require('socket.io')(server);
app.use(function(req, res, next){
res.io = io;
next();
});
...
module.exports = {app: app, server: server};
But the problem is when i m emitting an event as shown below. My client is reading the data multiple times.
routes/index.js
var clients = 0;
var nsp = res.io.of('/default-namespace');
nsp.on('connection', function (socket) {
clients++;
console.log(clients + ' clients connected!');
socket.on('disconnect', (reason) => {
clients--;
console.log(clients + ' clients connected!');
});
nsp.emit("socketToMe", "New User connected. Current clients:"+ clients);
});
My listener has the following code:
home.pug
var socket = io('/default-namespace');
socket.on('socketToMe', function (data) {
$('#data-div').append($('<li>').text(data));
});
Whenever i refresh the browser in another instance like incoginito my main browser is showing multiple events for the data. Like this
New User connected. Current clients:1
New User connected. Current clients:2
New User connected. Current clients:1
New User connected. Current clients:2
New User connected. Current clients:1
New User connected. Current clients:1
Not sure what is wrong. Can anyone help me on this?
Nodejs is event driven.The res object is not a global variable.
Express middleware runs for every request.
var clients = 0;
var nsp = res.io.of('/default-namespace');
nsp.on('connection', function (socket) {
clients++;
console.log(clients + ' clients connected!');
socket.on('disconnect', (reason) => {
clients--;
console.log(clients + ' clients connected!');
});
nsp.emit("socketToMe", "New User connected. Current
clients:"+clients);
});
Let me explain what happens above.A user requests and req handler is fired and you access the res object and you listen for events.
So for each request, you are listening for socket 'connection' event.That means you are setting multiple event listeners with the same name.Every time you make a request you set a new listener.
You are supposed to set only a single 'connection' listener.
This explains emitting the same event multiple times.
app.use(function(req, res, next){
res.io = io;
next();
});
Instead of using the above middleware function,listen directly on io instance

Cannot read property 'insert' of undefined when trying to put data in MongoDB

I'm getting this error: "Cannot read property 'insert' of undefined" when trying to insert data into a database. The error shows on:
db.coordinates.insert({ "x" : "data.x", "y" : "data.y"})
Database name - "node5"
Collection name - "coordinates"
// Including libraries
var app = require('http').createServer(handler);
var io = require('socket.io').listen(app);
var static = require('node-static'); // for serving files
//db connection
var MongoClient = require('mongodb').MongoClient;
var assert = require('assert');
var ObjectId = require('mongodb').ObjectID;
var mongo = require('mongodb');
var monk = require('monk');
var db = monk('localhost:27017/node5');
var url = 'mongodb://localhost:27017/node5';
MongoClient.connect(url, function(err, db) {
assert.equal(null, err);
console.log("Connected correctly to server.");
db.close();
});
// This will make all the files in the current folder
// accessible from the web
var fileServer = new static.Server('./');
// This is the port for our web server.
// you will need to go to http://localhost:8080 to see it
app.listen(8080);
// If the URL of the socket server is opened in a browser
function handler(request, response) {
request.addListener('end', function () {
fileServer.serve(request, response);
}).resume();
}
// Delete this row if you want to see debug messages
io.set('log level', 1);
// Listen for incoming connections from clients
io.sockets.on('connection', function (socket) {
// Listen for mouse move events
socket.on('post', function (data) {
console.log('posted');
console.log(data);
socket.broadcast.emit('posted', data); // Broadcasts event to everyone except originating client
db.coordinates.insert({ "x" : "data.x", "y" : "data.y"})
});
});
When writing an answer, please note that I'm new to node.js and I might not understand if you tell the answer in a complex way:)
If you are using monk for your project, then you can drop the mongodb module, since it's functionality is being wrapped up by monk. From Monk's documentation, you should be doing something like:
const monk = require('monk');
const db = monk('localhost:27017/node5')
const coordinates = db.get('coordinates');
Now that you have a reference to your coordinates collection, you can use it later in your code:
coordinates.insert({ x: data.x, y: data.y });
I hope this is easy enough to understand. If it is still confusing, then please comment below and I'll elaborate further :)

Send messages from server to client socket.io

I am trying to send a message from NodeJS server to client using socket.io
However, I found the same practice all over the internet, which is wrapping the emit with io.on('connection', handler) and then making the server listen on a special "channel" event like so:
var io = require('socket.io')();
var socketioJwt = require('socketio-jwt');
var jwtSecret = require('./settings').jwtSecret;
var User = require('./models/users').User;
io.set('authorization', socketioJwt.authorize({
secret: jwtSecret,
handshake: true
}));
var sockets = [];
io.on('connection', function(socket) {
sockets.push(socket);
});
sendLiveUpdates = function(gameSession) {
console.log(sockets);
}
exports.sendLiveUpdates = sendLiveUpdates;
exports.io = io;
My problem is: I want to emit messages outside this on connection wrapper, example from my routes or other scripts. Is it possible?
Thanks.
Yes. You just need to keep a reference to the socket.
// Just an array for sockets... use whatever method you want to reference them
var sockets = [];
io.on('connection', function(socket) {
socket.on('event', function() {
io.emit('another_event', message);
});
// Add the new socket to the array, for messing with later
sockets.push(socket);
});
Then somewhere else in your code...
sockets[0].emit('someEvent');
What I usually do is assign new clients a UUID and add them to an object keyed by this UUID. This comes in handy for logging and what not as well, so I keep a consistent ID everywhere.

How can I have faye-websockets code running in the browser?

I'm new with node.js/express and all and I want to be able to notify any clients in browser about a new message received from some algorithm in the back-end. The publisher algorithm connect to the websocket and writes the message.
As far as I've looked there were examples which recommended websockets but I haven't been able to run that code in browser only in console.
Example client code:
var WebSocket = require('faye-websocket');
var ws = new WebSocket.Client('ws://localhost:1234');
var http = require('http');
var port = process.env.PORT || 1235;
var server = http.createServer()
.listen(port);
// receive a message from the server
ws.on('message', function(event) {
alert(JSON.parse(event.data));
});
Thank you
Found the answer after some trial/error iterations.
The algorithm now does a POST to an URL which in turn triggers a write to sockets for all connected clients via socket.io.
Client code:
var socket = io('http://localhost:7777');
socket.on('message', function (msg) {
document.body.insertAdjacentHTML( 'beforeend', '<div id="myID">'+msg+'</div>' );
});
And on the server, when client connects I retain it's socket into an array so I can write to each one:
Server code:
io.on('connection', function(socket){
console.log('a user connected: '+socket.id);
var id = clientCount++;
clientSockets[id] = socket;
socket.on('disconnect', function(){
console.log('user disconnected');
delete clientSockets[id];
socket = null
});
});
app.post('/alerts', function(req, res) {
req.accepts(['json', 'application']);
console.log("Algo did a POST on /alerts!");
// send the message to all clients
//console.log(req.body);
for(var i in clientSockets) {
clientSockets[i].send(JSON.stringify(req.body));
}
res.send(200);
});
In conclusion, I'm not using faye-websockets but instead socket.io

Socket.io Identify User for Socket

I write some code example that identifi connected users via socket.io... So now I must write a code on index page to comunicate with users.
The code is below and HOW to send a message to user[1] "Welcome" and for user[2] "HI men" and also limit connection fr 2 users. so when 2 user connected then anybody else cant connect..
Index.html:
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect();
var users;
socket.on('hello', function (data) {
console.log(data.hello);
});
socket.on('listing', function (data) {
users = data;
});
socket.on('chat', function (message) {
console.log(message);
});
socket.on('message', function (message) {
console.log(message);
});
function chat (message) {
socket.emit('chat', message);
}
function message (user, message) {
socket.emit('message', {
user: user,
message: message
});
}
</script>
app.js
var express = require('express');
var app = express.createServer();
var io = require('socket.io').listen(app);
app.listen(3000);
app.use(express.static(__dirname));
var users = {};
var userNumber = 1;
function getUsers () {
var userNames = [];
for(var name in users) {
if(users[name]) {
userNames.push(name);
}
}
return userNames;
}
io.sockets.on('connection', function (socket) {
var myNumber = userNumber++;
var myName = 'user#' + myNumber;
users[myName] = socket;
socket.emit('hello', { hello: myName });
io.sockets.emit('listing', getUsers());
socket.on('chat', function (message) {
io.sockets.emit('chat', myName + ': ' + message);
});
socket.on('message', function (data) {
users[data.user].emit('message', myName + '-> ' + data.message);
});
socket.on('disconnect', function () {
users[myName] = null;
io.sockets.emit('listing', getUsers());
});
});
app.listen(process.env.PORT);
You can start by taking a look at how to configure authorization with Socket.io. The handshakeData provided by the callback can be modified there (ie: add a username property), and any changes will be accessible via socket.handshake in your app.js (via the object passed in to the callback for io.sockets.on('connection',..). Using request header information that's also accessible from the handshakeData, you can set user values within the authorization callback (ie: from a database) so you can identify the user for the given socket in your app.js.
Here's a similar example
I know it has been a long time since you asked this, but just 4 days ago I published a module for node js, express and socket.io which manages that exactly thing you wanted. Check the Usage and Example; I hope you will find this module helpful!
You can install it via NPM socket.io.users This is a node js module for socket.io applications. One user per client.
Some of the usage code:
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var socketUsers = require('socket.io.users');
// ...
socketUsers.Session(app); // IMPORTANT !
// ...
var rootIo = require('socket.io')(server); // default '/' as namespace.
var chatIo = rootIo.of('/chat');
var rootUsers = socketUsers.Users; /* default '/' as namespace.
Each namespace has ITS OWN users object list,
but the Id of a user of any other namespace may
have the same value if request comes from the same client-machine-user.
This makes easy to keep a kind of
synchronization between all users of all the different namespaces. */
var chatUsers = socketUsers.Users.of('/chat'); //
rootIo.use(socketUsers.Middleware());
/* IMPORTANT but no errors if you want
to skip it for a io.of(namespace)
that you don't want the socket.io.users' support. */
chatUsers.use(socketUsers.Middleware());
chatUsers.on('connected',function(user){
console.log(user.id + ' has connected to the CHAT');
user.store.username = 'username setted by server side'; /*at the store
property you can store any type of properties
and objects you want to share between your user's sockets. */
user.socket.on('any event', function(data){
/*user.socket is the current socket, to get all connected sockets from this
user, use: user.sockets */
});
chatIo.emit('set username',user.store.username);
});
rootUsers.on('connected',function(user){
console.log('User has connected with ID: '+ user.id);
});
rootUsers.on('connection',function(user){
console.log('Socket ID: '+user.socket.id+' is user with ID: '+user.id);
});
rootUsers.on('disconnected',function(user){
console.log('User with ID: '+user.id+'is gone away :(');
});
//...server.listen blabla..

Categories

Resources