node.js Query database using mongoose in socket.io - javascript

Right now, I'm writing a small web application using node.js with my partner. In the application, we need to query some data from database using mongoose, then, send the data to the client.Trying to do this, I'm using the code below:
io.sockets.on('connection', function (socket) {
var id = socket.id;
socket.on('request', function (data) {
mongoose.createConnection(dbConfig.url);
var ClassX = require("./models/" + data.request);
var class_query = ClassX.findOne({}, function (err, result) {
if (err) {
console.log("There is an error: "+ err);
return handleError(err);
}
if (!result) {
console.log("No result!");
}
io.sockets.to(id).emit("response", result);
});
});
});
But it doesn't work.
And when the code is running, the log file of the database show some information like below:
2017-02-23T15:40:48.426+0800 I NETWORK [thread1] connection accepted from 127.0.0.1:5015 #3 (3 connections now open)
2017-02-23T15:40:48.428+0800 I NETWORK [conn3] received client metadata from 127.0.0.1:5015 conn3: { driver: { name: "n
odejs", version: "2.2.24" }, os: { type: "Windows_NT", name: "win32", architecture: "x64", version: "10.0.14393" }, plat
form: "Node.js v6.9.5, LE, mongodb-core: 2.1.8" }
The information "[conn3] received client metadata ..." seems weird. And, from the experience of many attempts, I think the callback function of ClassX.finOne() has not been executed. And I totally don't know why.

Related

Nodejs + SocketIO + MySql Connections Not Closing Properly and Creating Database Overhead

I've been having this issue for over a couple of months now, and still can't seem to figure out how to fix it. It seems that I'm experiencing a high number of connections to our database, and I assume it's because our connections aren't closing properly which is causing them to hang for long periods of time. In return this causes a lot of overhead which occasionally causes our web application to crash. Currently the application runs the promise-mysql npm package to create a connection and query the database. Our web application uses socketio to request these connections to our mysql database.
I'm working with existing code that was here before me, so I did not set it up this way. This makes it a bit more confusing for me to debug this issue because I'm not that familiar with how the connections get closed after a successful / unsuccessful query.
When logging errors from our server I'm getting messages like this:
db error { Error: Connection lost: The server closed the connection.
at Protocol.end (/home/ec2-user/myapp/node_modules/mysql/lib/protocol/Protocol.js:113:13)
at Socket.<anonymous> (/home/ec2-user/myapp/node_modules/mysql/lib/Connection.js:109:28)
at Socket.emit (events.js:185:15)
at Socket.emit (domain.js:422:20)
at endReadableNT (_stream_readable.js:1106:12)
at process._tickCallback (internal/process/next_tick.js:178:19) fatal: true, code: 'PROTOCOL_CONNECTION_LOST' }
(Not sure if that has anything to do with the high number of connections I'm seeing or not)
I recently changed the wait_timeout and interactive_timeout to 5000 in MySql, which is way lower than the default 28800, but setting it to this stopped the application from crashing so often.
This is the code for creating the database connection:
database.js file
import mysql from 'promise-mysql';
import env from '../../../env.config.json';
const db = async (sql, descriptor, serializedParameters = []) => {
return new Promise( async (resolve, reject) => {
try {
const connection = await mysql.createConnection({
//const connection = mysql.createPool({
host: env.DB.HOST,
user: env.DB.USER,
password: env.DB.PASSWORD,
database: env.DB.NAME,
port: env.DB.PORT
})
if (connection && env.ENV === "development") {
//console.log(/*"There is a connection to the db for: ", descriptor*/);
}
let result;
if(serializedParameters.length > 0) {
result = await connection.query(sql, serializedParameters)
} else result = await connection.query(sql);
connection.end();
resolve(result);
} catch (e) {
console.log("ERROR pool.db: " + e);
reject(e);
};
});
}
export default db;
And this is an example of what the sockets look like:
sockets.js file
socket.on('updateTimeEntry', async (time, notes, TimeEntryID, callback) => {
try {
const results = await updateTimeEntry(time, notes, TimeEntryID);
callback(true);
//socket.emit("refreshJobPage", false, "");
}
catch (error) {
callback(false);
}
});
socket.on('selectDatesFromTimeEntry', (afterDate, beforeDate, callback) => {
const results = selectDatesFromTimeEntry(afterDate, beforeDate).then((results) => {
//console.log('selectLastTimeEntry: ', results);
callback(results);
})
});
And this is an example of the methods that get called from the sockets to make a connection to the database
timeEntry.js file
import db from './database';
export const updateTimeEntry = (time, notes, TimeEntryID) => {
return new Promise(async (resolve, reject) => {
try {
const updateTimeEntry = `UPDATE mytable SET PunchOut = NOW(), WorkTimeTotal = '${time}', Notes = "${notes}" WHERE TimeEntryID = '${TimeEntryID}';`
const response = await db(updateTimeEntry, "updateTimeEntry");
resolve(response[0]);
} catch (e) {
console.log("ERROR TimeEntry.updateTimeEntry: " + e);
reject(e);
}
});
};
//Gets a List for Assigned Jobs
export const selectDatesFromTimeEntry = (afterDate, beforeDate) => {
return new Promise(async (resolve, reject) => {
try {
const selectDatesFromTimeEntry = `SELECT * FROM mytable.TimeEntry WHERE PunchIn >= '${afterDate}' && PunchIn < '${beforeDate}';`
//console.log("Call: " + selectDatesFromTimeEntry);
const response = await db(selectDatesFromTimeEntry, "selectDatesFromTimeEntry");
//console.log("Response: " + response);
resolve(response);
} catch (e) {
console.log("ERROR TimeEntry.selectDatesFromTimeEntry: " + e);
reject(e);
}
});
};
I just really want to figure out why I'm noticing so much overhead with my database connections, and what I can do to resolve it. I really don't want to have to keep restarting my server each time it crashes, so hopefully I can find some answers to this. If anyone has any suggestions or knows what I can change in my code to solve this issue that would help me out a lot, thanks!
EDIT 1
These are the errors I'm getting from mysql
2020-04-30T11:12:40.214381Z 766844 [Note] Aborted connection 766844 to db: 'mydb' user: 'xxx' host: 'XXXXXX' (Got timeout reading communication packets)
2020-04-30T11:12:48.155598Z 766845 [Note] Aborted connection 766845 to db: 'mydb' user: 'xxx' host: 'XXXXXX' (Got timeout reading communication packets)
2020-04-30T11:15:53.167160Z 766848 [Note] Aborted connection 766848 to db: 'mydb' user: 'xxx' host: 'XXXXXX' (Got timeout reading communication packets)
EDIT 2
Is there a way I can see why some of these connections would be hanging or going idle?
EDIT 3
I've been looking into using a pool instead, as it seems that it is a more scalable and appropriate solution for my application. How can I achieve this with the existing code that I have?
You are opening a new connection for each and every query... Opening a connection is slow, there is a lot of overhead for doing so, and your server certainly does not have unlimited number of connections allowed. The NodeJS mysql package provides a pooling mechanism which would be a lot more efficient for you.
The goal is to reuse the connections as much as possible instead of always disposing of them right after the first query.
In your db.js, create a pool on startup and use it:
var pool = mysql.createPool({
connectionLimit : 10, //Number of connections to create.
host: env.DB.HOST,
user: env.DB.USER,
password: env.DB.PASSWORD,
database: env.DB.NAME,
port: env.DB.PORT
});
To execute your query, you would simply do this:
await pool;
return pool.query(sql, serializedParameters);

Mongoose query doesn't run when readyState is 1

I have written the following code, it's for a discord bot. When I call the command I get matchID in console for the first time. But when I call the command again I dont get any output. It gets stuck near the point where I have console.log("Stuck Here"). I new to mongoose so I don't know what to do.
if (mongoose.connection.readyState === 0) {
mongoose.connect(`mongodb://localhost/${server}`, {
useNewUrlParser: true
});
console.log('mongoose readyState is ' + mongoose.connection.readyState);
}
console.log("Stuck here!");
mongoose.connection.on("error", function (err) {
console.log("Could not connect to mongo server!");
return console.log(err);
});
mongoose.connection.on('connected', function (ref) {
console.log('Connected to mongo server.');
mongoose.connection.db.listCollections({
name: "matches"
}).next(function (err, collinfo) {
if (err) console.log(err);
if (collinfo) {
Matches.findOne({}, {}, {
sort: {
'created_at': -1
}
}, function (err, match) {
if (err) console.log(err);
console.log(`${match.matchID}`);
})
} else {
}
});
})
Mongoose is really meant to be used with a single database. It isn't impossible to create create multiple connections, or use multiple database, but it's not trivial either. For instance, you have to declare each of your models for each connection/database (see this answer, for instance).
It's probably much easier to use a single database, and adjust your models so they contain a property server that you can use as a key in all your queries.
So to check if there's a Matches document for server "X", you'd run Matches.findOne({ server : 'X' }).
You could also consider creating a separate model Servers that would store metadata for servers, and use references between the Matches and Servers models. More info on that here.

NodeJs Cassandra driver is getting stuck

I am trying to connect to a Cassandra cluster in NodeJs but when I execute a query, prepared or not, it just gets stuck. The callback isn't called at all and the process is just hanging. What could cause this? I am able to connect using devcenter using the same host/keyspace.
var Cassandra = require('cassandra-driver');
var cassandraClient = new Cassandra.Client({ contactPoints:['*.*.*.*'], keyspace: '*'});
cassandraClient.on('log', function(level, className, message, furtherInfo) {
console.log('log event: %s -- %s', level, message);
});
cassandraClient.connect(function (err) {
console.log(err)
});
console.log("Starting C* getting data");
cassandraClient.execute(query, params, {prepare: true}, function(err, result) {
if(err) console.log(err);
res = result;
console.log("Done C*");
console.log('result: ' + result.rows[0]);
notDone = false;
});
Output:
Init Get IP Info
log event: info -- Adding host *.*.*.*:9042
Starting C* getting data
And it gets stuck there. Any idea what is causing this?

AWS Cognito - offline data availability

I am building a phonegap app and use AWS Cognito to store the User data. In the description of Cognito, it is said, that the data is offline available. This does not work in my code:
var add_data;
function getCognitoData(){
var params = {
IdentityPoolId: COGNITO_IDENTITY_POOL_ID,
Logins: {
'graph.facebook.com': FACEBOOK_TOKEN
}
};
AWS.config.region = AWS_REGION;
AWS.config.credentials = new AWS.CognitoIdentityCredentials(params);
AWS.config.credentials.get(function(err) {
if (err) {
console.log("Error: "+err);
return;
}
console.log("Cognito Identity Id: " + AWS.config.credentials.identityId);
var syncClient = new AWS.CognitoSyncManager();
syncClient.openOrCreateDataset('myDataset', function(err, dataset) {
dataset.get('myKey', function(err, value) {
console.log(value, err);
});
add_data = function(thisid, thisval) {
dataset.put(thisid, thisval, function(err, record){
dataset.synchronize({
onSuccess: function(data, newRecords) {
console.log("success", newRecords);
},
onFailure: function(err) {
console.log("error", err);
},
onConflict: function(dataset, conflicts, callback) {
console.log("sync conflict", dataset, conflicts);
var resolved = [];
for (var i=0; i<conflicts.length; i++) {
resolved.push(conflicts[i].resolveWithRemoteRecord());
}
dataset.resolve(resolved, function() {
return callback(true);
});
}
});
});
}
});
});
}
The AWS Credentials for the Identity Pool and the Facebook Token are previously set, and work in the online mode, but I don't get the dataset data, when being offline.
Am I doing something wrong or is it generally not possible to get the Cognito Dataset data while being offline? I read, that the data is actually being held in the local storage.
I am using the current AWS SKD (Release v2.1.42) and the Amazon Cognito JS.
It's possible to get the data offline. You need to synchronize the dataset to get whatever contents may be inside, otherwise them being empty is expected. Are you doing that? If not, try doing that, but if so, can you update your code above?
There was a bug with the aws-sdk-js causing the offline bug. CognitoSync depends on aws-sdk-js. Should be working now as of aws-sdk-js#2.7.21. Make sure you update.

Why is my Meteor app logging to server but not client?

I'm building a meteor app that hooks into the twitter api and I've had no luck so far getting it to work. I'm using the twit package to make the call on the server side, and it logs the data to the server console, but when the client console goes to log it there is no data.
The client doesn't throw an error, it runs the console.log in the else statement for the result parameter, but it comes through as undefined. It's as if the result callback runs before the data comes back, but my understanding of the Meteor.call method is that it's supposed to wait until it hears back from the server before it runs.
What am I doing wrong here?
if (Meteor.isClient) {
Template.hello.greeting = function () {
return "Welcome to testing.";
};
Template.hello.recentFollows = function () {
return Session.get("recentFollows");
};
Template.hello.events({
'click #fetchButton': function () {
console.log("Recent tweets from stream!");
userName = "josiahgoff";
Meteor.call('getBananaTweets', function(err, result) {
if(err) {
console.log("error occurred on receiving data on server. ", err);
} else {
console.log("result: ", result);
Session.set("recentFollows", result);
}
});
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
Twit = new TwitMaker({
consumer_key: '******',
consumer_secret: '******',
access_token: '******',
access_token_secret: '******'
});
});
Meteor.methods({
getBananaTweets: function () {
Twit.get('search/tweets', { q: 'banana since:2011-11-11', count: 1 }, function(err, result) {
if (err) {
console.log("Error", err);
return err;
} else {
console.log(result);
return result;
}
});
}
});
}
You are using return in your server code in a place where it must not be used: in an asynchronous call-back. The Twit.get call returns immediately and the function ends (with no return value). So the client doesn't receive anything. Some time later the Twit.get comes back, but the return in that case goes nowhere.
This is a pretty common question. The solution is to wrap your Twit.get call into a fiber in some shape or form to make it synchronous. See for instance this answer: Iron Router Server Side Routing callback doesn't work

Categories

Resources