Ambiguous flow of node.js program execution - javascript

Please find the code below,
What i am still unable to understand in the code, is that why the browser keeps waiting for 10 seconds before executing the next query. Shouldn't it be just pass the sleep query to the database and then move on to execute the next one immediately?
var http = require('http');
var mysql = require('mysql');
http.createServer(function (request, response) {
var connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: 'pops',
dateStrings: 'true',
multipleStatements: 'true'
});
// Connect to MySQL (if there is an error, report it and terminate the request)
connection.connect (function (err) {
// connected! (unless `err` is set)
if (err !== null)
{
console.log('Error '+err.code);
}
else
{
console.log('Connection to database successful!');
}
});
connection.query("SELECT sleep(10);", function(err, rows) {
// There was a error or not?
if (err !== null)
{
console.log("Query Rrror:" + err);
}
else
{
// Shows the result on console window
console.log("called after 10 seconds");
}
});
connection.query("SELECT * FROM team", function(error, result) {
// There was a error or not?
if (error !== null)
{
console.log("Query Rrror:" + error);
}
else
{
// Shows the result on console window
response.writeHead(200, {"Content-Type": "text/html"});
length = result.length - 1;
for(var i = 0; i <= length; i++)
{
row_obj = result[i];
team_id = row_obj.id;
team_name = row_obj.team_name;
team_color = row_obj.color;
created_at = row_obj.created_at;
response.write('Team ID: ' + team_id + '<br />');
response.write('Team Name: ' + team_name + '<br />');
response.write('Team Color: ' + team_color + '<br />');
response.write('Creation Date: ' + created_at + '<br />');
response.write('<br /><br />');
}
response.end("OK");
}
});
// Close connection
connection.end();
}).listen(8080, "127.0.0.1");

First, you should create the mysql connection outside the httpRequest handler.
And yes, Node.JS will execute both queries without waiting, but what I think that is happening, is that node-mysql is queuing the query.

Related

Mutiple calls to database not working properly

I have two problems with mysql:
1 - After a 2 hours connected with mysql it stop to respond
2 - Multiple calls are not working properly
If you look to createandcall function it will enter in a for loop to call the server.
the first call works properly but all other is not working as expected and when a look into the logs, I see something like this:
RackChecker connected with database! Connection Closed RackChecker
connected with database! Connection Closed RackChecker connected with
database! Connection Closed RackChecker connected with database!
Connection Closed RackChecker connected with database! Connection
Closed RackChecker connected with database! Connection Closed
RackChecker connected with database! Connection Closed RackChecker
connected with database! Connection Closed RackChecker connected with
database! Connection Closed
and then the query results for all interactions, looks like the functions openconnection() and closeconnection() are being executed for all interactions while the first interactions didn't finish to process yet.
main.js:
function createandcall(rackname, racknameid, stb) {
$('#maintable').append('<table class="table"><tbody><tr style="text-align:center"><td><h2>' + rackname + '</h2><table class="table"><tbody style="text-align:left"><tr id="STBL"></tr><tr id="STBL1"></tr><tr id="STBL2"></tr><tr id="STBL3"></tr></tbody></table></td></tr></tbody></table>');
for (i = 1; i < stb + 1; i++) {
createtable(i);
callstb(rackname, racknameid, i);
}
return;
}
function callstb(rackname, racknameid, i) {
$.ajax({
type: "GET",
dataType: 'text',
url: "http://localhost:3000/index/" + rackname + ' ' + racknameid + ' ' + i,
success: function (data) {
response = '\#stb' + i;
idtd = '\#tdstb' + i;
$(response).html(data.replace(/\[32m/gi, '').replace(/\[0\;33m/gi, '').replace(/\[0m/gi, '').replace(/\[33m/gi, '').replace(/\[37m/gi, '').replace(/\[31m/gi, ''));
pre = $(response).html().toString();
},
error: function (error) {
$("#error").html('Error trying to get the STBs report');
$("#error").show();
}
})
}
server.js:
app.get('/index/*', (req, res) => {
parsedparam = req.params[0].split(" ")
rackname = parsedparam[0]
racknameid = parsedparam[1]
stb = parseInt(parsedparam[2])
verifystbs(rackname, racknameid, stb, res);
});
function openconnection() {
con.connect(() => { console.log("RackChecker connected with database!") });
}
function closeconnection() {
con.end(() => { console.log("Connection Closed") });
}
function verifystbs(rackname, racknameid, stb, res) {
openconnection();
con.query("SELECT (SELECT UCASE(name) FROM models WHERE s.model = id) as Model,\
(SELECT UCASE(name) FROM manufacturers WHERE s.manufacturer = id) as Branch,\
(SELECT UCASE(name) FROM racks WHERE s.rack = id) as Rack,\
s.name as Stb,\
x.pr as Jira, \
x.reason as Reason,\
x.requestor AS Stress_Request,\
x.version as Version\
FROM \
stbs s \
LEFT JOIN \
stressrun x \
ON (s.active = 1 && s.rack = (SELECT id FROM racks WHERE name = '"+ racknameid + "')) \
WHERE x.id = (SELECT max(id) FROM stressrun y WHERE y.stb_id = s.id) and s.name like ('STB_%"+ stb + "')\
and x.reason in ('failed','other','new build') ORDER BY s.name;", (err, result) => {
console.log(result)
if (!Array.isArray(result) || !result.length) {
callnewstb = shell.exec('./shellscript/callnewstb.sh ' + rackname + ' ' + stb, { async: true });
callnewstb.stdout.on('data', (data) => {
res.send(data);
});
}
else {
for (i = 0; i < result.length; i++) {
parsestbnumber = result[i].Stb.split("_");
stbnumber = parseInt(parsestbnumber[1]);
stbnumber = stbnumber * 1;
if (stb == stbnumber) {
res.send("Stress Test is not running on <b>" + result[i].Stb + "</b><br>Reason: <b>" + result[i].Reason + "</b><br>Jira Ticket: <b><a href='https://link.jira.com/browse/" + result[i].Jira + "'>" + result[i].Jira + "</a></b><br>Build Version: <b>" + result[i].Version)
break
}
else {
callnewstb = shell.exec('./shellscript/callnewstb.sh ' + rackname + ' ' + stb, { async: true });
callnewstb.stdout.on('data', (data) => {
res.send(data);
})
}
}
}
});
closeconnection();
}
I found an answer, I changed the method that I was using to connect to the database
I started to use createPool() instead of createConnection()
const mysql = require('mysql');
var pool = mysql.createPool({
connectionLimit: 16,
host: "localhost",
user: "user",
password: "password",
database: "test"
});
function verifystbs(rackname, racknameid, stb, res) {
pool.getConnection((err, connection) => {
if (err) { console.log(err) }
connection.query("select * from table", result)
connection.release();
});
});

NJS-024: memory allocation failed in OracleDB - Nodejs

I am trying to run a query using OracleDB with Nodejs to get the view populated in the UI but I get a NJS-024: memory allocation failed error. Can someone help me out? The view contains 120 columns in total and when I query the view in SQL Developer, it works just fine.
ConnectionPool.js:
var path = require('path');
var oracledb = require('oracledb');
var poolMap = {};
var logger = require(path.join(global.root + '/app/util/logger.js'))();
function createPool(poolName, config, callback) {
oracledb.createPool(
config,
function(err, p) {
if (err){
logger.error(err);
return;
}
poolMap[poolName] = p;
callback(poolMap[poolName]);
}
);
}
function getPool(poolName) {
return poolMap[poolName];
}
module.exports = {
createPool: createPool,
getPool: getPool
};
This is my poolAttributes:
var pool;
oracledb.prefetchRows = 10000;
oracledb.maxRows = 400000;
var poolAttrs = {
user: dbcfg.username,
password: dbcfg.password,
connectString: dbcfg.connectionString,
connectionClass : 'Report API',
poolMin : 3,
poolMax : 10,
poolIncrement: 2,
poolTimeout : 600 //seconds
};
connectionPool.createPool("Reports", poolAttrs, function(connPool){
pool = connPool;
logger.info("Pool created by reports.");
});
This is my code:
router.post('/report/', jsonParser, function (req, res) {
var data = req.body,
startRow = data.startRow,
numRows = data.numRows,
sortCol = data.sortCol,
sortDir = data.sortDir;
var countQuery = 'SELECT COUNT(*) ' +
'FROM this_view ' ;
var query = 'SELECT * ' +
'FROM this_view' ;
var seg,
orderBy,
offset;
orderBy = ' ORDER BY UPPER(' + sortCol + ') ' + sortDir;
offset = ' OFFSET ' + startRow + ' ROWS FETCH NEXT ' + numRows + ' ROWS ONLY';
query += orderBy;
query += offset;
logger.info("Begin: " + (new Date().toString()));
async.parallel({
rows: function (callback) {
pool.getConnection(function (err, connection) {
logger.info("Begin Connection: " + (new Date().toString()));
if (err) {
logger.error(err.message);
return;
}
logger.info("Begin execute: " + (new Date().toString()));
connection.execute(
query,
{},
{
resultSet: true,
prefetchRows: 1000
},
function (err, results) {
logger.info("End execute: " + (new Date().toString()));
var rowsProcessed = 0;
var startTime;
if (err) {
logger.error(err.message);
callback("Something broke in the first thing");
doRelease(connection);
return;
}
var procJson = [];
function fetchRowsFromRS(connection, resultSet, numRows) {
resultSet.getRows(
numRows, // get this many rows
function (err, rows) {
if (err) {
console.error(err);
doClose(connection, resultSet); // always close the result set
} else if (rows.length >= 0) {
/**
* For each row in the result, pushes a new object to the rows array
* In each new object, the key is assigned and the result row value set
*/
for (var i = 0; i < rows.length; i++) {
procJson.push({});
console.log(procJson);
for (var j = 0; j < resultSet.metaData.length; j++) {
procJson[i][resultSet.metaData[j].name.toLowerCase()] = rows[i][j];
}
}
//TODO: Add null handling
logger.info("Send JSON: " + (new Date().toString()));
logger.info("JSON Sent: " + (new Date().toString()));
if (rows.length === numRows) // might be more rows
fetchRowsFromRS(connection, resultSet, numRows);
else
doClose(connection, resultSet); // always close the result set
} else { // no rows
doClose(connection, resultSet); // always close the result set
}
});
}
fetchRowsFromRS(connection, result.resultSet, numRows);
callback(null, procJson);
});
});
},
totalRows: function (callback) {
pool.getConnection(function (err, connection) {
logger.info("Begin Connection: " + (new Date().toString()));
if (err) {
logger.error(err.message);
return;
}
logger.info("Begin execute: " + (new Date().toString()));
connection.execute(
countQuery,
function (err, result) {
logger.info("End execute: " + (new Date().toString()));
if (err) {
logger.error(err.message);
callback("Something broke");
doRelease(connection);
return;
}
logger.info("Send JSON: " + (new Date().toString()));
console.log(result.rows);
callback(null, result.rows[0][0]);
logger.info("JSON Sent: " + (new Date().toString()));
doRelease(connection);
});
});
}
}, function(err, result){
if(err){
logger.error(err);
}
res.send(result);
});
});
If rows.length >=0 and if the query returns 0 results, I get this.
How much memory does your Node.js server have? You're setting maxRows very high and grabbing all the data in a single shot. This is likely causing you to run out of memory. Generally, the key is to balance round trips (which you want to reduce) with memory usage (which goes up as round trips are reduced.
You'll want to leverage the ResultSet API, which allows you to stream a read-consistent view of data in smaller chunks. Have a look at this for ideas: https://jsao.io/2015/07/an-overview-of-result-sets-in-the-nodejs-driver/
Rather than buffer the data in the Node.js server (which would lead to the same problem), you'll want to stream it down to the http request.
Finally, but perhaps most importantly, note that your code is currently open to SQL injection. Values that come in from users via req.body cannot be trusted. They must either be bound in using bind variables OR sanitized using something like dbms_assert.
Only values (like numRows) can be bound in. Identifiers (like sortCol) have to be sanitized. You'll likely want to do the sanitization in Node.js, so here's a really basic check that should help.
You could create an "assert" module:
function simpleSqlName(name) {
if (name.length > 30) {
throw new Error('Not simple SQL');
}
// Fairly generic, but effective. Would need to be adjusted to accommodate quoted identifiers,
// schemas, etc.
if (!/^[a-zA-Z0-9#_$]+$/.test(name)) {
throw new Error('Not simple SQL');
}
return name;
}
module.exports.simpleSqlName = simpleSqlName;
function validSortOrder(order) {
if (order !== 'desc' && order !== 'asc') {
throw new Error('Not valid sort order');
}
return order;
}
module.exports.validSortOrder = validSortOrder;
Then your code would look more like this (notice I'm using both the assert module and bind variables):
let assert = require('assert.js');
router.post('/report/', jsonParser, function (req, res) {
var data = req.body,
startRow = data.startRow,
numRows = data.numRows,
sortCol = assert.simpleSqlName(data.sortCol),
sortDir = assert.validSortOrder(data.sortDir);
var countQuery = 'SELECT COUNT(*) ' +
'FROM this_view ' ;
var query = 'SELECT * ' +
'FROM this_view' ;
var seg,
orderBy,
offset;
orderBy = ' ORDER BY UPPER(' + sortCol + ') ' + sortDir;
offset = ' OFFSET :start_row ROWS FETCH NEXT :num_rows ROWS ONLY';
query += orderBy;
query += offset;
logger.info("Begin: " + (new Date().toString()));
async.parallel({
rows: function (callback) {
pool.getConnection(function (err, connection) {
logger.info("Begin Connection: " + (new Date().toString()));
if (err) {
logger.error(err.message);
return;
}
logger.info("Begin execute: " + (new Date().toString()));
connection.execute(
query,
{
start_row: startRow,
num_rows: numRows
},
function (err, result) {
logger.info("End execute: " + (new Date().toString()));
if (err) {
logger.error(err.message);
callback("Something broke in the first thing");
doRelease(connection);
return;
}
console.log(result.rows);
var procJson = [];
/**
* For each row in the result, pushes a new object to the rows array
* In each new object, the key is assigned and the result row value set
*/
for (var i = 0; i < result.rows.length; i++) {
procJson.push({});
for (var j = 0; j < result.metaData.length; j++) {
procJson[i][result.metaData[j].name.toLowerCase()] = result.rows[i][j];
}
}
logger.info("Send JSON: " + (new Date().toString()));
callback(null, procJson);
logger.info("JSON Sent: " + (new Date().toString()));
doRelease(connection);
});
});
},
totalRows: function (callback) {
pool.getConnection(function (err, connection) {
logger.info("Begin Connection: " + (new Date().toString()));
if (err) {
logger.error(err.message);
return;
}
logger.info("Begin execute: " + (new Date().toString()));
connection.execute(
countQuery,
function (err, result) {
logger.info("End execute: " + (new Date().toString()));
if (err) {
logger.error(err.message);
callback("Something broke");
doRelease(connection);
return;
}
logger.info("Send JSON: " + (new Date().toString()));
console.log(result.rows);
callback(null, result.rows[0][0]);
logger.info("JSON Sent: " + (new Date().toString()));
doRelease(connection);
});
});
}
}, function(err, result){
if(err){
logger.error(err);
}
res.send(result);
});
});
Learn more about bind variables here: https://github.com/oracle/node-oracledb/blob/master/doc/api.md#bind
Also, check out the slides from a recent talk I gave. You may get something out of them... https://www.dropbox.com/s/2rhnu74z2y21gsy/Tips%20and%20Tricks%20for%20Getting%20Started%20with%20the%20Oracle%20Database%20Driver%20for%20Node.pdf?dl=0

Node.js: "process run out of memory"

I have the following code which leads to the error: FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory
It doesn't make any difference whether I set --max_old_space_size=4096 (or bigger numbers) or not. I have 16 GB RAM on my PC.
System: win10/node.js 6.9.2/mongodb 3.4
I have over 16 000 000 messages in the "chatModel". With a smaller amount of messages the code works.
Do you have any suggestions how to solve the problem/optimize the code?
function sortOutMessages(){
var atSymbol = "#";
var rgx = new RegExp("^\\" +atSymbol);
chatModel.find({messageContent: rgx}, function (err, doc){
var docs = doc;
var docsLength = docs.length;
for (var i =0; i<docsLength;i++) {
var directedMessagesObj = new directedMessagesModel
({
timeStamp: docs[i].timeStamp,
channelName: docs[i].channelName,
userName: docs[i].userName,
userID: docs[i].userID,
messageContent: docs[i].messageContent,
messageLength: docs[i].messageLength,
subscriber: docs[i].subscriber,
turbo: docs[i].turbo,
moderator: docs[i].moderator
});
directedMessagesObj.save({upsert:true}, function (err) {
var fs = require('fs');
if (err) {
fs.appendFile("undefinedLog.txt", "error at " + new Date().toLocaleString() + " directedMessagesObj.save " + "\r\n")
loggerWinston.warn("error at " + new Date().toLocaleString() + " directedMessagesObj.save " + "\r\n");
return console.log(err);
}
});
}
});
}
You are creating docs.length amount of new Promise with this code. What you should be doing instead is to limit the amount of Promise that can be running.
Since what you have been trying to write is a synchronous code, I would advise calling the next dbSave in the callback of the previous one.
If you are after a parallel system, I would create a simple semaphore system.
I advise
module.exports.asyncEach = function(iterableList, callback, done) {
var i = -1,
length = iterableList.length;
function loop() {
i++;
if (i === length) {
done();
return;
}
callback(iterableList[i], loop);
}
loop();
};
then you call asyncEach with async save model is very beter
Thank you all for your answers! I decided to go a different way and it works for now:
var cursor = chatModel.find({messageContent: rgx}).cursor();
cursor.on('data',function (doc) {
var directedMessagesObj = new directedMessagesModel
({
timeStamp: doc.timeStamp,
channelName: doc.channelName,
userName: doc.userName,
userID: doc.userID,
messageContent: doc.messageContent,
messageLength: doc.messageLength,
subscriber: doc.subscriber,
turbo: doc.turbo,
moderator: doc.moderator
});
directedMessagesObj.save({upsert:true},function (err) {
var fs = require('fs');
if (err) {
fs.appendFile("undefinedLog.txt", "error at " + new Date().toLocaleString() + " directedMessagesObj.save " + "\r\n");
loggerWinston.warn("error at " + new Date().toLocaleString() + " directedMessagesObj.save " + "\r\n");
return console.log(err);
}
});
});

node.js / express app - which async method to use to replace my nested calls to HGET?

Background
I'm just learning node js and have run into a situation where I need to make up to two back to back calls to my redis database, depending on the results of the first query.
The code I have right now works.. but it's very ugly. I wrote it this way because I'm not good with async 'stuff'. But now that it's working... I want to refactor in a way that is readable and of course, in a way that works.
Here's the code, along with an explanation of what I'm trying to do:
Code
router.get('/:ip', function(req, res, next) {
var ip = req.params.ip;
if ( ! validate_ipV4(ip) ) {
res.status(400).send("Invalid IP");
return;
}
var three_octets = extract_octets(ip, 3);
var two_octets = extract_octets(ip, 2);
if (debug) { winston.log('info', 'emergency router.get() attempting hget using :' + three_octets); }
redis.hget("e:" + three_octets, 'ccid', function (e, d) {
if (e){
winston.log('error', 'hget using key: ' + octets + ' failed with error: ' + e);
res.status(500).send("Database query failed");
return;
}
if (d) {
if (debug) { winston.log('info', 'HGET query using ip: ' + ip + ' returning data: ' + d ) };
res.status(200).send(JSON.stringify(d));
return;
} else {
//retry using only 2 octets
redis.hget("e:" + two_octets, 'ccid', function (e, d) {
if (e){
winston.log('error', 'hget using key: ' + octets + ' failed with error: ' + e);
res.status(500).send("Database query failed");
return;
}
if (d) {
if (debug) { winston.log('info', 'HGET query using ip: ' + ip + ' returning data: ' + d ) };
res.status(200).send(JSON.stringify(d));
return;
}else {
res.status(404).send("Unknown IP");
return;
}
});//end hget
}
});//end hget
});
Explanation:
Accept an ip address as input. 10.1.1.1
Try to query the database for a hash that matches the first three octets. For example: "hget e:10.1.1 ccid"
If i have a match, I can return the db results and exit. otherwise, if the query came back with no results, then I need to retry using the first two octets: "hget e:10.1 ccid"
if that returns nothing, then i can exit the GET method.
ASYNC
I know that there is an async module... and i've tried to use MAP before. But from what I understand, you cannot force MAP to exit early.
So for example, if I did something like this:
async.map(ipOctets, hash_iterator, function (e, r) {
})
where ipOctets was an array with both 10.1.1. and 10.1 in it, if the first query found a match in the database, there's no way I can stop it from running the second query.
Can you give me some pointers on how to improve this code so that I don't have to repeat the same code twice?
I also thought of putting the redis.hget call into a separate function... like this:
var hash_get = function (hash, key, field) {
if (debug) { winston.log('info', 'hash_get() invoked with : ' + hash + ' ' + key + ' ' + field);}
redis.hget(hash + key, field, function (e, d) {
if (e){
winston.log('hash_get() failed with: ' + e);
return 500;
}
if (d) {
return (d);
}else {
return 404;
}
});
}
But again, I'm not sure how to do the following in a synchronous way:
call it from router.get
check results
repeat if necessary
Sorry for the noob questions.. but any pointers would be appreciated.
EDIT 1
Since posting, i found this http://caolan.github.io/async/docs.html#some
and I'm currently testing to see if this will work for me.
But please comment if you have some suggestions!
Thanks.
You could use the waterfall method which cascades functions into each other. I really only like to use it when I have 3 nested callbacks or more, otherwise I don't feel like it simplifies it enough.
After looking at your code and seeing how much you can reuse I think I would use async.until though.
router.get('/:ip', function(req, res, next) {
var ip = req.params.ip;
if (!validate_ipV4(ip)) {
res.status(400).send("Invalid IP");
return;
}
let success = false;
let octets_num = 3;
async.until(
// Test this for each iteration
function() { return success == true || octets < 2}, // You would adjust the test to set limits
// Do this until above
function(callback) {
let octets = extract_octets(ip, octets_num);
redis.hget("e:" + octets, 'ccid', function(e, d) {
if(e) {
winston.log('error', 'hget using key: ' + octets + ' failed with error: ' + e);
res.status(500).send("Database query failed");
}
else if(id) {
if (debug) { winston.log('info', 'HGET query using ip: ' + ip + ' returning data: ' + d ) };
res.status(200).send(JSON.stringify(d));
success == true;
}
else
{
octects_num--;
}
callback(null);
});
}
// After success or not found within 3 or 2 octets
function(err, result) {
if(success == false) {
res.status(404).send("Unknown IP");
return;
}
}
...
}
This permits you to reuse the same chunk of code with minimal variation. It's rough and I don't have the rest of your application to test it, but I hope you get the idea.
Maybe like this:
router.get('/:ip', function (req, res, next) {
var ip = req.params.ip;
if (!validate_ipV4(ip)) {
res.status(400).send("Invalid IP");
return;
}
var three_octets = extract_octets(ip, 3);
var two_octets = extract_octets(ip, 2);
//if (debug) { winston.log('info', 'emergency router.get() attempting hget using :' + three_octets); }
var hash = "e:"
var field = 'ccid';
async.waterfall([
function (callback) {
hash_get(hash, three_octets, field, callback)
},
function (d, callback) {
if (d) {
callback(null, d);
return;
}
hash_get(hash, two_octets, field, callback)
}
], function (err, result) {
if (err) {
winston.log('error', err.message);
res.status(err.status).send(err.message);
return;
}
if (result) {
res.status(200).send(JSON.stringify(result));
return;
}
res.status(404).send("Unknown IP");
return;
});
});
var hash_get = function (hash, key, field, callback) {
if (debug) { winston.log('info', 'hash_get() invoked with : ' + hash + ' ' + key + ' ' + field); }
redis.hget(hash + key, field, function (e, d) {
if (e) {
callback({ status: 500, message: 'hget using key: ' + key + ' failed with error: ' + e });
return;
}
if (d) {
if (debug) { winston.log('info', 'HGET query using ip: ' + ip + ' returning data: ' + d) };
callback(null, d);
} else {
callback(null, null);
}
});
}
Check Async.waterfall() for this as you want the result of one callback into another (http://caolan.github.io/async/docs.html#waterfall).
Async.map could not be used as it will hit both the octets at the same time
which you don't want .
Code
router.get('/:ip', function(req, res, next) {
var ip = req.params.ip;
if ( ! validate_ipV4(ip) ) {
res.status(400).send("Invalid IP");
return;
}
var three_octets = extract_octets(ip, 3);
var two_octets = extract_octets(ip, 2);
var redis_hget=function(octets){
redis.hget("e:"+octets,'ccid',function(e,d){
callback(null,d)
})
}
if (debug) { winston.log('info', 'emergency router.get() attempting hget using :' + three_octets); }
async.waterfall([
function(callback){
redis_hget(three_octets)
},
function(d,callback){
if(d)
callback(d)
else
redis_hget(two_octets)
}
],function(err,result){
if(err){
winston.log('error', 'hget using key: ' + octets + ' failed with error: ' + e);
res.status(500).send("Database query failed");
return;
}else{
if(result){
if (debug) { winston.log('info', 'HGET query using ip: ' + ip + ' returning data: ' + d ) };
res.status(200).send(JSON.stringify(d));
return;
}else{
res.status(404).send("Unknown IP");
return;
}
}
})
}

MySQL, Node.js Sequential actions - How can I do that?

I've the following code:
function query1() {
var defered = Q.defer();
console.log("In query1");
var connection = mysql.createConnection({
host: '........',
user: 'm...c....a.....i',
password: '......Z....9...K',
database: '.....ol'
});
connection.connect(function(err) {
if (!err) {
console.log("Database is connected ...");
} else {
console.log("Error connecting database ...");
}
});
sql = '' +
'select c.ID as CENA_ID, ' +
' c.I_KEY as CENA_NUMERO, ' +
' c.NM_CENA as CENA_NOME, ' +
' b.DS_MAC as MAC_BOX, ' +
' v.DS_CLIENTID as ALEXA_ID, ' +
' v.FK_ID_GRUPO as GRUPO_ID ' +
' from TB_DISPOSITIVOS_VOZ v ' +
' inner join TB_GRUPOS g ' +
' on g.ID = v.FK_ID_GRUPO ' +
' inner join TB_CENAS c ' +
' on g.ID = c.FK_ID_GRUPO ' +
' inner join TB_CENTRAIS b ' +
' on g.ID = b.FK_ID_GRUPO ' +
'where v.DS_CLIENTID = "' + userId + '" ' +
'and lower(c.NM_CENA) like "%' + sceneName.toLowerCase() + '%"';
console.log("Created query");
try{
connection.query(sql, function(erro, rows, fields) {
if (!erro) {
console.log("Executed query verifying the userId");
contador = 0;
if (rows.length > 0) {
cena_id = rows[0].CENA_ID;
cena_numero = rows[0].CENA_NUMERO;
cena_nome = rows[0].CENA_NOME;
alexa_id = rows[0].ALEXA_ID;
grupo_id = rows[0].GRUPO_ID;
mac_box = rows[0].MAC_BOX;
contador = contador + 1;
}
console.log("contador: " + contador);
} else {
console.log("Error - getting the Alexa register in database" + erro);
context.fail("Error - getting the Alexa register in database" + erro);
}
});
}catch (ex){
console.log("exception: " + ex);
}
}
And this code as well:
Q.all([query1()]).then(function(results) {
console.log("Q.all log function");
if (contador > 0) {
console.log("contador > 0");
var client = mqtt.connect('mqtt://.............com');
console.log("connected to MQTT broker");
var buffer = [26,
0,0,0,0,555,645,0,0,0,0,0,
0,5555,2,Math.floor((Math.random() * 200) + 1),
0,0,0,333,13,4,0,1,0,
cena_numero
];
console.log("Created buffer");
client.on('connect', function() {
client.publish('n/c/' + mac_box + '/app', buffer);
console.log("sent MQTT");
});
speechOutput = "Command " + sceneName + " executed successfully";
repromptText = "";
console.log("Process executed successfully")
} else {
console.log("contador <= 0");
speechOutput = "This command was not found!";
repromptText = "";
}
}, function (reason) {
console.log("reason: " + reason);
});
How can I do for the second code execute only if the first query1() executed correctly? Because in the function query1() i've a MySQL Query, and I only can continue with the process after the result of this query.
Anyone can help me?
Thanks a lot!
You're missing some key concepts regarding callbacks and asynchronous behavior in Node.js. You're using the "Q" library (btw I'd recommend trying bluebird instead) to handle promises, but your "query1" function does not return a promise. That's why query1 executes but your "Q.all log function" will execute before query1 is finished.
You can structure your code like this instead (I'll give an example with bluebird since I'm more familiar with it):
var Promise = require('bluebird');
var _connection;
function query1() {
return new Promise(resolve, reject) {
//open your connection
connection.open(function (err, connection) {
if (err) return reject(err);
_connection = connection;
//do your query
_connection.query(sql, [params], function (err, data) {
if (err) return reject(err);
else resolve(data);
});
});
});
}
function query2(data) {
return new Promise(resolve, reject) {
//do your query, using data passed in from query1
_connection.query(sql, [params], function (err, data) {
if (err) return reject(err);
else resolve(data);
});
});
}
query1
.then(function (data) { query2(data); })
.catch(function (err) {
console.log('error:', err);
});
Also, just FYI, concatenating SQL string like this is a no-no that will open you up to a SQL injection attack:
like "%' + sceneName.toLowerCase() + '%"
Instead, use like "%?%" and call your SQL with connection.query(sql, [sceneName], function(err, data) {}). Hope this helps.
I solved my problem with asyncpackage like this:
var async = require('async');
async.series([
function(callback) {
//action 1...
},
function(callback){
//action 2...
}
], function(err) {
if (err) {
speechOutput = "Scene not found!";
repromptText = "Please try again.";
}
console.log("Before speechOutput");
callback(sessionAttributes,
buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
});

Categories

Resources