NodeJs promises returning too early - node.js

I'm new to NodeJs and code I'm working with is using Q framework for promises.
And it seems that I don't understand the 'Q' framework too well, I'm running into a case when promises are returning too early.
Here is my code:
BridgeInfo.getBridgeInfo(exten)
.then(function processBridgeInfo(bridge_info) {
console.log("Nitesh -- bridge info is back, yay");
if (bridge_info !== undefined) {
conf_bridge = new VoxConfBridge(ari);
conf_bridge.init(bridge_info);
/**Add the bridge to the bridgeList**/
bridgeList[conf_bridge.bridge.id] = conf_bridge;
console.log("Bridge ID to register is "+ conf_bridge.bridge.id);
self.registerEvents(conf_bridge.bridge);
conf_bridge.registerUser(event, false, channel);
} else {
console.log("Unknown extension [" + exten + "] blocking it");
ChannelDriver.blockChannel(ari, channel.id);
}
})
.catch(function handleError(err) {
console.error("Nitesh -- [voxbridgemanager] error occured "+err);
});
The above code calls a function getBridgeInfo, this function is supposed to do some DB queries and return the result.
Here is the code in getBridgeInfo
BridgeInfo.getBridgeInfo = Q.async(function(bridge_identifier) {
console.log("Nitesh -- Getting the bridge info for ["+ bridge_identifier + "]");
if (bridge_identifier !== undefined) {
db.getConfBridgeProfile(bridge_identifier)
.then(function processBridgeProfile(result) {
if (result !== undefined) {
console.log("Nitesh -- Bridge Info is "+ JSON.stringify(result));
var bridge_info = new BridgeInfo();
bridge_info.init(result)
.then (function bridgeInfoInitDone() {
return bridge_info;
})
.catch( function handleError(err) {
console.error("Nitesh ---[bridgeInfoInit] Error is "+ err);
});
}
else {
console.log("Can't find any bridge profile for this identifier ["+ bridge_identifier + "]");
}
}, function handleError(err) {
console.error("Failed to retrieve bridgeInfo");
});
} else {
console.error("Received an invalid identifier");
}
});
**When I run this code, I see that in my main code,which calls getBrigeInfo, it hits its catch error handler even before getBRidgeInfo has executed completely, getBridgeInfo's SQL query results appear afterwards.
I think the way I'm using promises isn't being done correctly, any explanations please

Your missing the key part of what promises can do.
You should not need to do any catch statements in your getBridgeInfo. You should return the whole promise that gets the SQL data... and handle it in your first block of code BridgeInfo.getBridgeInfo(exten)
Assuming that db.getConfBridgeProfile(bridge_identifier); returns a promise
Example:
BridgeInfo.getBridgeInfo = function(bridge_identifier) {
console.log("Nitesh -- Getting the bridge info for ["+ bridge_identifier + "]");
if (bridge_identifier !== undefined) {
return Q.fcall(function () {
throw new Error("Received an invalid identifier");
});
}
return db.getConfBridgeProfile(bridge_identifier);
}
I've also seperated out your process query... keep things simple.
BridgeInfo.processBridgeProfile = function(result) {
if (result !== undefined) {
console.log("Nitesh -- Bridge Info is "+ JSON.stringify(result));
var bridge_info = new BridgeInfo();
return bridge_info.init(result);
}else{
return Q.fcall(function () {
throw new Error("Can't find any bridge profile for this identifier ["+ bridge_identifier + "]");
});
}
Return promises and handle the catch in the main function. Your getting stuck in handling a catch, the SQL results are not getting returned like they should.
Call:
BridgeInfo.getBridgeInfo(bridge_identifier).then(function(result){
return BridgeInfo.processBridgeProfile(result)
}).then(function(){
//Do the rest here
}).catch(function(){
//One catch to rule them all :)
});

Related

superagent-q post does not execute, fails silently

var request = require('superagent-q');
createWordFrequency(name, freq) {
return request.post(this.hostname + "/api/frequency/" + name)
.send({'freq': freq}).end()
.then(function(res) {
if (!res.ok) throw new Error(res.status);
console.log("success:"+JSON.stringify(res.body));
return res.body.word;
});
}
The post call is never made and there is no effect. A breakpoint inside then() does not trigger and the request is never made. I cannot step into the post() call in the debugger.
Also tried:
createWordFrequency(name, freq) {
return request.post(this.hostname + "/api/frequency/" + name)
.send({'freq': freq})
.end(function(err, res) {
if (err) throw new Error(err);
console.log("success:"+JSON.stringify(res.body));
return res.body.word;
});
}

setTimeout() in Node.js

I am writing cloud functions on Cloud Firestore triggers. What I want is when a document is added under some uuid it has to deleted after 2 minutes and assign the same data to another document. I wrote some code regarding that like below
exports.createdOpenOrder = functions.firestore.document('Some/{psId}/Open/{OrderId}').onCreate((snap, context) => {
// Get an object representing the document
console.log("Deleting function execution started:");
const newValue = snap.data();
var OrderId = context.params.OrderId;
var psId = context.params.psId;
setTimeout(delete_cur, 120000);
function delete_cur() {
var data = db.collection('Some').doc(psId).collection('Open').doc(OrderId).delete().then(function() {
console.log("Document successfully deleted!");
// calling another function to reassign
reassign(OrderId);
return;
}).catch(function(error) {
console.error("Error removing document: ", error);
return;
});
}
});
Now my problem is the setTimeout function is not calling exactly after 2 minutes and data is not deleting. Is anything wrong with my code? Please let me know how to write code work perfectly on setTimeout.
To find the problem, put log before, and a catch around, the contents of your setTimeout handler.
Currently you are only trapping exceptions after the delete async function returns. All other exceptions in the chain, before calling delete, are not caught.
function delete_cur() {
console.log('handler called')
try {
var data = db.collection('Some').doc(psId).collection('Open').doc(OrderId).delete().then(function() {
console.log("Document successfully deleted!");
// calling another function to reassign
reassign(OrderId);
return;
}).catch(function(error) {
console.error("Error removing document: ", error);
return;
});
} catch (e) {
console.error('could not invoke delete', e)
}
}

I can't make this promise work

I am trying to use Promises instead of Callback in my Lambda Function in NodeJs 4.3. What I'm trying to do is read a config file from S3 and use the configuration to connect to a DB and execute a SELECT statement on a table. When I test the function, I don't get any errors in the console.
I have defined my function as follows:
function setUpConnection(response) {
console.log("S3 Response " + JSON.stringify(response));
return new Promise(function(resolve, reject) {
config = response.Body.toString('utf-8');
config = JSON.parse( config );
// set up connection from S3 config file
var con = mysql.createConnection({
host: config.hostaddress,
user: config.user,
password: config.pass,
database: config.dbname
});
console.log("connection " + JSON.stringify(con));
console.log("config " + JSON.stringify(config));
// create connection
con.connect(function(err){
if(err){
// Output connection details for debugging
console.log('Error connecting to DB');
return Promise.reject(new Error(output));
}
});
// Run Select Query
con.query("SELECT * FROM goodsreceiptheader WHERE invoiceKey = ?", [invoicekey], function(err,res){
if(err){
console.log(err);
con.end();
return Promise.reject(new Error(output));
}
if ( res.length <= 0 ){
console.log('Response Object ' + JSON.stringify(res));
con.end();
return Promise.reject(new Error(output));
}
resolve(res);
})
})
}
The function is being called by this function:
// Setup goodsreceipt info
var goodsreceipt = data.goodsreceipt;
getObjectPromise = s3bucket.getObject(params).promise()
getObjectPromise
.then(setUpConnection)
.then(validateRecord)
.catch(callback(null, Error))
When I execute this code, I am only seeing the result of the code
console.log("S3 Response " + JSON.stringify(response));
on the second line. Is there a problem with the way I configured setUpConnection?
You're using rejection in a wrong way.
return Promise.reject(new Error(output));
Should be replaced with
reject(new Error(output));
return;
Also catch call looks strange: it calls callback immediately. Usually catch block looks like that:
somePromise.catch((error) => {
console.error(error); // If output required.
callback(error); // If callback provided.
});
Move con.query call inside of con.connect callback.
First of all, from where output is coming? I don't see it anywhere defined.
Second of all it is considered as good practice to always throw/reject with an instance of Error, in your example i guess, at least by variable name, output is not an instance of Error. Third thing in general only valid use case in my opinion of using new Promise constructor is when you want to transform callback api to promise which you are doing here (which is good) or you when deal with setTimeout/setInterval
Anyway you are using Promise.reject where you have reject in scope already which is not how you should reject your promise in this case. Next thing is that you are using con.query outside of callback that is provided to con.connect which effectively means you are calling query before connection was successfully established, try with something like:
return new Promise(function(resolve, reject) {
...
con.connect(function(err){
if(err){
return reject(new Error('...'));
}
// Run Select Query
con.query(..., ..., function (err,res) {
if(err){
...
return reject(new Error('...'));
}
if (res.length <= 0 ){
...
return reject(new Error(output));
}
return resolve(res);
})
});
})
Few sides notes:
1. Check does this lib have promise api, probably it should in that way you dont need to promisify things around on your own.
2. If it doesnt have you can always use libs like bluebird to promisfy code for you
You rejection of promise is wrong
Try in this way
function setUpConnection(response) {
console.log("S3 Response " + JSON.stringify(response));
return new Promise(function(resolve, reject) {
config = response.Body.toString('utf-8');
config = JSON.parse( config );
// set up connection from S3 config file
var con = mysql.createConnection({
host: config.hostaddress,
user: config.user,
password: config.pass,
database: config.dbname
});
console.log("connection " + JSON.stringify(con));
console.log("config " + JSON.stringify(config));
// create connection
con.connect(function(err){
if(err){
// Output connection details for debugging
console.log('Error connecting to DB');
return reject(err);
}
});
// Run Select Query
con.query("SELECT * FROM goodsreceiptheader WHERE invoiceKey = ?", [invoicekey], function(err,res){
if(err){
console.log(err);
con.end();
return reject(err);
}
if ( res.length <= 0 ){
console.log('Response Object ' + JSON.stringify(res));
con.end();
return reject('response less 0');
}
resolve(res);
})
})
}

Node / Express & Postgresql - when no rows match

Hello I am new to Postgresql and I wanted to learn how one handles 0 results as an error is thrown. Essentially I want to get a user if it doesn't exist, return null if one doesn't, and have an error handler. Below is the current code I am using. Any tips on a better way to do this are appreciated!
var options = {
// Initialization Options
promiseLib: promise
};
var pgp = require('pg-promise')(options);
var connectionString = 'postgres://localhost:5432/myDbName';
var db = pgp(connectionString);
function getUser(id) {
let user = new Promise(function(resolve, reject) {
try {
db.one('select * from users where loginName = $1', id).then(function(data) {
console.log(data);
resolve(data);
}).catch (function (e) {
console.log('error: '+e);
reject(e);
});
}
catch (e) {
console.log('error: '+e);
reject(e);
}
});
return user;
}
output in console:
error: QueryResultError {
code: queryResultErrorCode.noData
message: "No data returned from the query."
received: 0
query: "select * from users where loginName = 'someUserName'"
}
I am the author of pg-promise.
In the realm of promises one uses .then to handle all normal situations and .catch to handle all error situations.
Translated into pg-promise, which adheres to that rule, you execute a database method that resolves with results that represent all the normal situations, so anything else ends up in .catch.
Case in point, if returning one or no rows is a normal situation for your query, you should be using method oneOrNone. It is only when returning no row is an invalid situation you would use method one.
As per the API, method oneOrNone resolves with the data row found, or with null when no row found, which you can check then:
db.oneOrNone('select * from users where loginName = $1', id)
.then(user=> {
if (user) {
// user found
} else {
// user not found
}
})
.catch(error=> {
// something went wrong;
});
If, however, you have a query for which returning no data does represent an error, the proper way of checking for returning no rows would be like this:
var QRE = pgp.errors.QueryResultError;
var qrec = pgp.errors.queryResultErrorCode;
db.one('select * from users where loginName = $1', id)
.then(user=> {
// normal situation;
})
.catch(error=> {
if (error instanceof QRE && error.code === qrec.noData) {
// found no row
} else {
// something else is wrong;
}
});
Similar considerations are made when choosing method many vs manyOrNone (method any is a shorter alias for manyOrNone).
Type QueryResultError has a very friendly console output, just like all other types in the library, to give you a good idea of how to handle the situation.
In your catch handler for the query, just test for that error. Looking at pg-promise source code, a code of noData is 0. So just do something like this:
db.one('select * from users where loginName = $1', id).then(function(data) {
console.log(data);
resolve(data);
}).catch (function (e) {
if(e.code === 0){
resolve(null);
}
console.log('error: '+e);
reject(e);
});

MongoDB: Waiting for available socket hanging

So I am using Mongoose's findOneAndUpdate to update a key value in a document. I am needing to increment that number by one. If it's not in there it should create a new document. It's in a post route in Node.
I have information going to the post route on a button click. My app requires users to click a button multiple times in succession and i'm getting a Waiting for available sockets... at the bottom of my browser and everything hangs.
I am just doing this on my localhost. At the end of the request once everything "unhangs" I get the following error in my console:
POST http://localhost:3000/api/songsqueued net::ERR_EMPTY_RESPONSE
This is the post route i'm working with:
router.post('/api/songsqueued', function(req, res){
Song.findOneAndUpdate({songId: req.body.songId}, { $inc:{queueTimes: 1} },
function(err, song){
if (err) {
return console.log("Error: " + err)
}
if(song){
song.queueTimes += 1;
song.save(function(err){
if(err){
console.log(err)
} else {
console.log("updated fam")
}
});
} else {
var song = new Song();
song.artistName = req.body.artistName;
song.titleName = req.body.titleName;
song.songId = req.body.songId;
song.songImg = req.body.songImg;
song.save(function(err) {
if (err) {
console.log("Error: " + err)
} else {
console.log("created fam")
}
})
console.log(song);
return res.json({message: "SongCreated"})
}
})
})
Any ideas on how to remedy this?
Your node server needs to send a response to the client in order for the response to complete. If you don't send a response, the connection will timeout and you get the socket hangup. Make sure that you send a response for each condition:
if (err) {
return res.status(500).end("some error message");
}
else if (song) {
return res.status(200).end("updated");
}
else {
return res.status(201).end("created");
}

Resources