Im having troubles where my node app all a sudden starts to consume a lot of CPU. Im suspecting that the function below gets stuck somehow..
Client.prototype.countActiveChatsRedis = function (userID, agentID, obj, callback) {
var count = 0;
pub.keys("widgetActive:" + userID + ":*", function(err, key) {
if(err !== null) {
console.log("Redis error..... --> " + err);
callback(count, obj);
}
if(key && key.length > 0) {
pub.mget(key, function(err, data) {
if(data) {
for(var i = 0; i < data.length;i++) {
if(data[i]) {
var arr = data[i].split(",");
if(arr[2] == agentID) {
if (Number(arr[3]) > 0) {
count++;
}
}
}
}
callback(count, obj);
}
});
} else {
callback(count, obj);
}
});
}
Any ideas what the problem could be? Any case where it could avoid sending the callback?
This function runs around 50 times per second.
It is bad practice to use KEYS in a production environment. To quote the Redis master himself:
Warning: consider KEYS as a command that should only be used in
production environments with extreme care. It may ruin performance
when it is executed against large databases. This command is intended
for debugging and special operations, such as changing your keyspace
layout. Don't use KEYS in your regular application code. If you're
looking for a way to find keys in a subset of your keyspace, consider
using SCAN or sets.
Whenever you add a key with this prefix, just add it to a set called "widgetActive" the user's id or any other data you need.
you can also use HASH if you need to save some data for each entry.
you should always return your callbacks to make sure that your function terminates correctly and returns the control to the calling context:
Client.prototype.countActiveChatsRedis = function (userID, agentID, obj, callback) {
var count = 0;
pub.keys("widgetActive:" + userID + ":*", function(err, key) {
if(err !== null) {
console.log("Redis error..... --> " + err);
return callback(count, obj);
}
if(key && key.length > 0) {
pub.mget(key, function(err, data) {
if(data) {
for(var i = 0; i < data.length;i++) {
if(data[i]) {
var arr = data[i].split(",");
if(arr[2] == agentID) {
if (Number(arr[3]) > 0) {
count++;
}
}
}
}
return callback(count, obj);
}
});
} else {
return callback(count, obj);
}
});
}
It's stucked because in the case where there is no data, no callback is being called.
pub.mget(key, function(err, data) {
if(data) {
for(var i = 0; i < data.length;i++) {
if(data[i]) {
var arr = data[i].split(",");
if(arr[2] == agentID) {
if (Number(arr[3]) > 0) {
count++;
}
}
}
}
// callback(count, obj); // <==== move this callback outside of if (data)
}
callback(count, obj); // this ensures that callback always gets called
});
Related
I am trying to finish my script, but for some reason i don't know, it refuses to execute in the order i put it in.
I've tried placing a 'wait' function between the JoinRequest update function and the following code, but when run, it acts as if the function call and wait function were the other way round, countering the point of the wait().
const Roblox = require('noblox.js')
var fs = require('fs');
var joinRequests = []
...
function wait(ms) {
var d = new Date();
var d2 = null;
do { d2 = new Date(); }
while(d2-d < ms*1000);
};
...
function updateJReqs() {
Roblox.getJoinRequests(4745601).then((array) => {
var i;
var final = [];
for(i = 0; i < array.length; i++) {
final.push(array[i].username);
};
if(final === '') {
final = '-None';
};
joinRequests = final
console.log('Updated join requests.')
});
}
function check() {
setTimeout(() => {
fs.readFile('Request.txt',encoding = 'utf-8', function(err, data) {
if (err) {
check();
} else {
updateJReqs(); //for some reason this function is executed alongside the below, not before it.
// Tried putting wait(x) in here.
console.log('Request received: ' + data)
var solution = joinRequests
console.log('Fuffiling request with ' + solution)
fufillRequest(solution)
fs.unlink('Request.txt', function(err) {
if(err) throw err;
});
check();
}
});
}, 400)
}
check();
The script is supposed to wait until a file is created (accomplished), update the list of join requests (accomplished) and then create a new file with the list of join requests in(not accomplished).
if I understand your code you work with async code, you need to return a promise in updateJReqs and add a condition of leaving from the function because you have an infinite recursion
function updateJReqs() {
return new Promise(resolve => {
Roblox.getJoinRequests(4745601).then((array) => {
var i;
var final = [];
for(i = 0; i < array.length; i++) {
final.push(array[i].username);
};
if(final === '') {
final = '-None';
};
joinRequests = final
console.log('Updated join requests.')
resolve();
});
}
}
async function check() {
setTimeout(() => {
fs.readFile('Request.txt',encoding = 'utf-8', function(err, data) {
if (err) {
await check();
} else {
await updateJReqs();
// Tried putting wait(x) in here.
console.log('Request received: ' + data)
var solution = joinRequests
console.log('Fuffiling request with ' + solution)
fufillRequest(solution)
fs.unlink('Request.txt', function(err) {
if(err) throw err;
});
// you dont have an exit from your function check();
return 'Success';
}
});
}, 400)
}
check().then(res => console.log(res));
When I pass an array with 1 element everything works great, when I pass one with two (max for our use case) I get the following error:
There's no write queue for that file descriptor (after write)!
Here is my code:
exports.triggerPhysical = function(state, alerts) {
console.dir("IN PHYSICAL");
console.dir(alerts);
SerialPort.list(function(err, ports) {
var port = {};
for(var i = 0; i < ports.length; i++) {
try {
if(typeof ports[i].manufacturer != 'undefined' && ports[i].manufacturer.includes("Numato")) {
port = ports[i];
}
} catch(err) {
console.dir(err);
}
}
var numato = new SerialPort(port.comName, {baudrate : 19200}, function(err) {
if(err) {
return console.dir(err);
}
console.dir('calling write');
for(var j = 0; j < alerts.length; j++) {
numato.write('relay ' + state + ' ' + alerts[j].index + '\r', function(err) {
if(err) {
console.dir('error writing');
console.dir(err);
}
console.dir('serial message written');
});
}
numato.close();
return true;
});
});
}
First write works great, second one fails. I am guessing there is an obvious solution but I am not finding it. Any insight would be much appreciated.
I ended up doing two things to resolve this issue. First I upgraded to version 5.x of the node-serialport library.
Second, I changed my code to the following:
exports.triggerPhysical = function(state, alerts) {
var port = new SerialPort('/dev/ttyACM0');
port.on("open", function() {
alerts.forEach(function(alert, idx) {
str = 'relay ' + state + ' ' + alert.index + '\r';
port.write(str, function(err, results) {
if(err) {
console.dir("err writing");
console.dir(err);
} else {
console.dir(results);
}
});
});
})
port.drain(writeDone);
function writeDone() {
console.dir("In writeDone");
port.close();
}
}
I am now able to do consecutive writes without causing any errors and the port doesn't end up in a weird locked state.
I am new to nodejs. please help me how to save the data in foreach loop and send response back to controller.it returns false not return object. Thanks in advance
Here is my code like
var rideStatus = require('../models/ridestatus');
module.exports = {
invite_ride: function* (body) {
var saved = false;
var receivers = body.uids;
receivers = receivers.split(',').filter(function(n) { return n != 'null'; });
receivers.forEach(function* (n) {
yield rideStatus.findOne(
{$and: [{ride_id: body.rideid}, {receiver_id: receivers}]},
function(err, doc) {
if (doc === null) {
new rideStatus({
ride_id: body.rideid,
invited_id: body.userId,
receiver_id: receivers,
}).save(function(err1, ridestatus) {
if (!err1) {
rideStatus.findOne({_id: ridestatus._id}).
populate('ride_id').
populate('invited_id').
populate('receiver_id').
exec(function(err2, user) {
// console.log(user);
if (user != null) {
saved = user;
}
});
}
});
}
});
});
return saved;
},
};
because of the asynchronous nature of node.js your "return save" statement won't wait for your i/o to complete his work. and also note that if you have multiple values to be saved, you should return an array of saved Users objects.
var rideStatus = require('../models/ridestatus');
module.exports = {
invite_ride: function* (body) {
var savedUsers = [];
var receivers = body.uids;
receivers = receivers.split(',').filter(function(n) { return n != 'null'; });
var len = receivers.length
var i=0
receivers.forEach(function* (n) {
yield rideStatus.findOne(
{$and: [{ride_id: body.rideid}, {receiver_id: receivers}]},
function(err, doc) {
if (doc === null) {
new rideStatus({
ride_id: body.rideid,
invited_id: body.userId,
receiver_id: receivers,
}).save(function(err1, ridestatus) {
if (!err1) {
rideStatus.findOne({_id: ridestatus._id}).
populate('ride_id').
populate('invited_id').
populate('receiver_id').
exec(function(err2, user) {
// console.log(user);
if (user != null) {
savedUsers.push(user);
}
if(i==len-1)
return savedUsers;
else
i++
});
}else{
i++
}
});
}else{
i++
}
});
});
},
};
Look at library on the link: async
This is my code want to access callback variable newID outside calling-function. I want to insert bulk data into mongodb using batch with auto incremented id instead of default object
for (var i = 0; i < sizeOfResult; ++i) {
var newKey = {}; //Main json array
newKey = {
date: result[i]['date'],
issue: result[i]['issue'],
status: result[i]['status']
};
getNextSequenceValue("inventoryid",db, function(err, newID) {
newKey["_id"] = newID; <!-- try to add/assign callback variable(newID) into newKey -->
});
console.log("newKey: %j", newKey); <!-- but unable to get access callback variable(newID) here below-->
batch.insert(newKey);
}
// This is my called function
function getNextSequenceValue(name,db,callback) {
var ret = db.collection('counters_inv').findAndModify({ _id: name },null,{ $inc: { sequence_value: 1 } }, {new: true},
function(err,doc ) {
if(err){
return callback(err) // callback on error
}
callback(null, doc.value.sequence_value); // callback on success
});
}
Look at this code, you just need to put the variable outside and it works:
let i = 1
function functionwithcallback(callback) {
console.log(i)
i++
callback(i)
}
for (let j = 1; j <= 10; j++) {
functionwithcallback(() => {
if (j == 10)
console.log('done')
})
}
I'm not sure what the overall objective is, but the reason your newKey variable is not set correctly is because where it is being used has executed before the variable is set. In your example, your for loop is going to completely finish running kicking off a bunch of getNextSequenceValue() method calls that will eventually come back and run the callback code. It does not wait on the getNextSequenceValue function to finish before continuing the loop.
Solution: moving the console.log() and batch.insert() into the callback.
Here's an example that would execute in the correct order.
var keys = [];
for (var i = 0; i < sizeOfResult; ++i) {
var newKey = {
date: result[i]['date'],
issue: result[i]['issue'],
status: result[i]['status']
};
getNextSequenceValue("inventoryid", db, function(err, newID) {
newKey["_id"] = newID;
keys.push(newKey);
if (keys.length === sizeOfResult) {
console.log("keys: %j", keys);
batch.insertAll(keys);
}
});
}
function getNextSequenceValue(name, db, callback) {
db.collection('counters_inv').findAndModify({ _id: name }, null, { $inc: { sequence_value: 1 } }, {new: true},
function(err,doc) {
if(err){
return callback(err);
}
callback(null, doc.value.sequence_value);
});
}
I am looking for a clean way to structure my node.js code for the following situation. I thought of using EventEmitters to create a "workflow" type of thing. Also I thought of using one of the async libraries out there, that has been less thought out though.
Problem:
Looking for a piece of data
check cache, if found return
check db, if found return (store in cache)
get live data and return, (store in db, cache)
I mocked something up quickly using event emitters below.
var util = require("util");
var events = require('events');
var CheckForData = function() {
events.EventEmitter.call(this);
this.checkForData = function(key) {
this.emit("checkForDataRequest", key);
}
var _checkCache = function(key) {
if (key === 'cache') {
this.emit("found", {data:'cached data'});
}
else {
console.log("not found in cache "+key);
this.emit("checkDatastore", key);
}
}
var _chechDatastore = function(key) {
if (key === 'db') {
this.emit("found", {data:'db data'});
this.emit("storeCache", key, {data:'db data'});
}
else {
console.log("not found in db "+key);
this.emit("getData", key);
}
}
var _getData = function(key) {
if (key === 'live') {
this.emit("found", {data:'live data'});
this.emit("storeData", key, {data:'live data'});
}
else {
console.log("not found in live "+key);
this.emit("notFound", key);
}
}
var _storeData = function(key, data) {
this.emit("storeDb", key, data);
this.emit("storeCache", key, data);
}
var _storeDb = function(key, data) {
console.log("storing data in db. for "+key);
console.log(data);
}
var _storeCache = function(key, data) {
console.log("storing data in cache. for "+key);
console.log(data);
}
var _found = function(data) {
return data;
}
var _notFound = function(key) {
return key;
}
this.on("checkForDataRequest", _checkCache);
this.on("checkDatastore", _chechDatastore);
this.on("getData", _getData);
this.on("found", _found);
this.on("notFound", _notFound);
this.on("storeData", _storeData);
this.on("storeDb", _storeDb);
this.on("storeCache", _storeCache);
};
util.inherits(CheckForData, events.EventEmitter);
module.exports = new CheckForData();
To test it...
var checkForData = require('./check-for-data');
checkForData.on("found", function(data) {
console.log("Found data ");
console.log(data);
});
checkForData.on("notFound", function(key) {
console.log("NOOO Found data for " + key);
});
console.log("-------");
checkForData.checkForData('cache');
console.log("-------");
checkForData.checkForData('db');
console.log("-------");
checkForData.checkForData('live');
console.log("-------");
checkForData.checkForData('other');
console.log("-------");
Then async.js, i made a quick checkSeries which is basically the async.detectSeries but instead of returning the item in the collection return the result. See below...
var async = require('async');
function check_cache(key) {
console.log('checking cache');
return null;
}
function check_datastore(key) {
console.log('checking datastore');
return null;//{data: "db data"};
}
function check_api(options) {
console.log('calling api');
return {data: "live data"};
}
function exists(item, callback) {
callback(item());
}
async.checkSeries([check_cache, check_datastore, check_api], exists, function(result) {
// result now equals the first function that return data
console.log(result);
});
Any suggestions, hints, tips, ...? Is there a pattern or library that i am missing? Do you think it be possible/easier to do in Step, flow, ...? Memoize?
That seems like a lot of work for the caller and a lot of extra code that doesn't seem to be adding much value. I have something that looks like this in my model.
Foo.get = function (id, cb) {
var self = this;
// check the cache first
cache.get('foo:' + id, function (err, cacheFoo) {
// if found, just return it
if (!err && cacheFoo) {
return cb(null, cacheFoo);
}
// otherwise get from db
self.findOne({id: id}, function (err, dbFoo) {
if (err || !dbFoo) {
return cb(new Error('Foo not found', 404));
// you could do get live call here
}
// and store in cache
cache.store('foo:' + id, dbFoo);
return cb(null, dbFoo);
});
});
};
Callers can then always just call Foo.get(id, callback) and they don't have to care how it is actually retrieved. If it gets more complicated, you could use an async library (such as the aptly named async) to make the code more readable, but this should still be completely hidden from the caller.