AWS Lambda: How to call Mysql Query in sequence - node.js

I want to call more than one sql queries in sequence.
I have tried with below code but getting timeout error:
exports.handler = function (event, context, callback) {
getNumber()
.then(result1 => {
// Use result1
return getNumber1(); // (A)
})
.then(result2 => { // (B)
console.log(result2);
callback(null, "OK");
})
.catch(error => {
console.log(error);
callback(null, "OK");
});
};
function getNumber() {
return new Promise(function(resolve, reject) {
connection.query("SELECT 1+1 as test ", (error, data) => {
if (error) {
reject(error);
} else {
resolve(data);
}
});
});
}
function getNumber1() {
return new Promise(function(resolve, reject) {
connection.query("SELECT 1+2 as test ", (error, data) => {
if (error) {
reject(error);
} else {
resolve(data);
}
});
});
}
Here I'm getting 'Task timed out after 3.00 seconds' error.
So anyone can help me to call connection.query synchronously.

This can be solved by chaining of AWS Lambda functions.
So in this case, each function has to be separated into different lambda functions. Then call them in a chain.
Still, keep in mind that Lambda functions have the time limit and will exit. So you may need different architecture/AWS component to achieve this if the Lambda running time is more.
Invoke multiple aws lambda functions

Related

Query redshift cluster using NodeJs asynchronously

My task is to copy few redshift tables from cluster one to a new cluster.
For this I am writing a script in nodejs.
I am using aws-sdk RedshiftData api to fetch the data.
I have two separate queries which I want to run in parallel. Following is my code
class syncRedShiftNodes {
constructor(){ ... }
readDataOne(){
let newSqlQuery = `select * from ${this.tableName} limit 10`;
const params = {
ClusterIdentifier: clusterIdentifier,
Sql: newSqlQuery,
Database: database,
DbUser: dbUser
};
return new Promise((resolve, reject)=>{
return awsRedshift.executeStatement(params, function(err, res){
if (err) console.log(err, err.stack); // an error occurred
else{
return awsRedshift.getStatementResult({Id:res.Id}, function(error, data){
if (error) console.log(error, error.stack); // an error occurred
else return data;
});
}
});
});
}
readDataTwo(){ ...//identical to above function except the query }
main(){
return Promise.all([this.readDataOne(), this.readDataTwo()])
.spread((data1, data2)=>{
console.log("promise resolved!!");
return true;
}
}
The problem is that my code is never reaching the "promise resolved" log. If I put a log in the callback of the redshift getStatementResult, that is being printed correctly but my handle is never reaching the promise.all().then statement which I am not able to understand why so.
Another question I had in mind was is it a good practice to use such a pattern inside a class?
You didn't resolve or reject your promise inside the class.
Example below
class syncRedShiftNodes {
constructor() {}
readDataOne() {
let newSqlQuery = `select * from ${this.tableName} limit 10`;
const params = {
ClusterIdentifier: clusterIdentifier,
Sql: newSqlQuery,
Database: database,
DbUser: dbUser,
};
return new Promise((resolve, reject) => {
awsRedshift.executeStatement(params, function (err, res) {
if (err) {
console.log(err, err.stack);
reject(err);
} else {
awsRedshift.getStatementResult(
{ Id: res.Id },
function (error, data) {
if (error) {
console.log(error, error.stack);
reject(error);
} else {
resolve(data);
}
}
);
}
});
});
}
readDataTwo() {}
async main() {
try {
const result = await Promise.all([
this.readDataOne(),
this.readDataTwo(),
]);
return result;
} catch (err) {
console.log(err);
}
}
}

How to make a function return both a promise and a callback

Today, when I was working with node, I met some special async functions with "overloads" that accept both promises and callbacks. Like this:
doSomething(result => {
console.log(result)
})
doSomething()
.then(result => console.log(result))
And probably this:
const result = await doSomething()
console.log(result)
I tried to implement this in my code but was unsuccessful. Any help would be appreciated.
You can make a function like this by creating a promise, then chaining on that promise with the argument if there is one, and then returning that chained promise. That will make it call the callback at the appropriate time, as well as giving you access to the promise that will complete when the callback completes. If you want the original promise even when there's a callback (not the chained version), then you can return that instead, by still chaining but then returning the original promise instead.
function f(cb) {
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve(123), 1000);
});
if (cb) {
return promise.then(cb);
} else {
return promise;
}
}
// usage 1
f(console.log)
// usage 2
f().then(console.log)
Let's say you had a function that was going to read your config file and parse it and you wanted to support both versions. You could do that like this with two separate implementation inside. Note, this has full error handling and uses the nodejs calling convention for the callback that passes parameters (err, result):
function getConfigData(filename, callback) {
if (typeof callback === "function") {
fs.readFile(filename, function(err, data) {
try {
if (err) throw err;
let result = JSON.parse(data);
callback(null, result);
} catch(e) {
callback(err);
}
});
} else {
return fs.promises.readFile(filename).then(data => {
return JSON.parse(data);
}).
}
}
This could then be used as either:
getConfigData('./config.json').then(result => {
console.log(result);
}).catch(err => {
console.log(err);
});
configData('./config.json', (err, data) => {
if (err) {
console.log(err);
} else {
console.log(data);
}
});
Depending upon the specific asynchronous operation, it may be better or more efficient to have two separate implementations internally or to have one implementation that you adapt at the end to either a callback or a promise.
And, there's a useful helper function if you adapt a promise to a callback in multiple places like this:
function callbackHelper(p, callback) {
if (typeof callback === "function") {
// use nodejs calling convention for callbacks
p.then(result => {
callback(null, result);
}, err => {
callback(err);
});
} else {
return p;
}
}
That lets you work up a simpler shared implementation:
function getConfigData(filename, callback) {
let p = fs.promises.readFile(filename).then(data => {
return JSON.parse(data);
});
return callbackHelper(p, callback);
}

Waiting for promises: NodeJS + Express [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
How can I wrap an existing node.js api (an npm module: PythonShell) into a promise to make it synchronous. Here is my attempt (based on other similar questions):
new Promise(function(resolve, reject) {
PythonShell.run('./script.py', (err, results) => {
resolve(results); // no errors in this case
})
}).then(r => {
return r;
});
All inside a normal function. This returns a promise for some reason, I expect it to return the value of r.
It returns a promise because this is a Promise. You need to wait for the Promise to resolve by putting your code in the then or by using async/await. A Promise does not make your code synchronous.
For example
function run() {
return new Promise((resolve, reject) => {
PythonShell.run('./script.py', (err, results) => {
if (err) {
return reject(err)
}
return resolve(results);
})
})
}
async function main() {
const results1 = await run();
// Or
run().then((results2) => {
// Do something with results2 here, not outside out this block
})
}
main()
Create an async function/Promise to get the result from your script:
const getValue = () => {
return new Promise((resolve, reject) => {
PythonShell.run('./script.py', null, (err, results) => {
if(err) reject(err);
else resolve(results);
});
});
}
and the you can call it like:
getValue()
.then((r) => {
console.log("Result is => ", r);
// Do Something with r
})
.catch((e) => {
console.log("Error while fetching value: ", e);
});
Hope this helps :)

How to chain promise in array

I need help with ES6 Promises chaining in array processing.
How to process/define each item of array which goes into Promise.all method, when there is other async method inside resolve?
Here is simplified example:
function getData(data, callback) {
let groupPromises = data.map(row => {
var coordinates = getCoordinates(row);
return Promise.resolve({
"place": getPlaces(coordinates), //how to invoke this method
"data": row
};
});
Promise.all(groupPromises)
.then(groups => callback(groups))
.catch(err => console.log(err));
}
}
function getPlaces(coordinates) {
return new Promise(function(resolve, reject) {
if(coordinates == null) {
reject();
}
parameters = {
location: [coordinates.latitude, coordinates.longitude],
rankby: "distance",
};
googlePlaces.searchPlace(parameters, function (error, response) {
if (error) {
reject(error);
};
resolve(response);
});
}
}
You can do it like this where you add a .then() handler to your first promise that gets the place and then when that's available returns the object you want. The resolved results of your Promise.all() will then be the array of objects you want:
function getData(data, callback) {
let groupPromises = data.map(row => {
var coordinates = getCoordinates(row);
// add .then() handler here to convert the place result
// into the object you want it in
return getPlaces(coordinates).then(place => {
return {place: place, data: row};
});
});
return Promise.all(groupPromises)
.then(groups => callback(groups))
.catch(err => {
console.log(err);
throw err;
});
}
}
function getPlaces(coordinates) {
return new Promise(function(resolve, reject) {
if(coordinates == null) {
reject();
}
parameters = {
location: [coordinates.latitude, coordinates.longitude],
rankby: "distance",
};
googlePlaces.searchPlace(parameters, function (error, response) {
if (error) {
reject(error);
};
resolve(response);
});
}
}
FYI, since you're converting over to promises, why not just return the promise from getData() and not use a callback there at all? Your current code has no way of communicating back an error from getData() which is something that comes largely for free with promises.
In fact with pure promises, getData() could be simplified to this:
function getData(data, callback) {
return Promise.all(data.map(row => {
return getPlaces(getCoordinates(row)).then(function(place) {
return {place: place, data: row};
});
}));
}

NodeJS Promises - "Then" not called

I'm new to NodeJS and after spending a few hours trying to understand how Promises work exactly, what seems to be an easy thing still doesn't work.
I'm trying to make a few calls to a database, and once all of those calls are done, do something else. What I have now is the following code, but none of the then-functions are called.
var queries = ['SELECT value FROM tag', 'SELECT url FROM download_link'];
console.log("Starting promises");
var allPromise = Promise.all([queryDatabaseAddToResult(connection, queries[0], result), queryDatabaseAddToResult(connection, queries[1], result)]);
allPromise.then(
function(result) {
console.log("1"); // Does not show up
}, function(err) {
console.log("2"); // Does not show up either
}
);
function queryDatabaseAddToResult(connection, query, result) {
return new Promise(function(resolve, reject) {
connection.query(query, function(err, rows, fields) {
if (err) {
console.log(err);
Promise.reject(err);
}
console.log(rows);
result.tags = JSON.stringify(rows);
Promise.resolve(result);
});
})
}
The calls to the database do get made, as logging the rows show up in the log.
The problem is that you are not calling the correct resolve and reject functions. It should be:
function queryDatabaseAddToResult(connection, query, result) {
return new Promise(function(resolve, reject) {
connection.query(query, function(err, rows, fields) {
if (err) {
console.log(err);
reject(err);
} else {
console.log(rows);
result.tags = JSON.stringify(rows);
resolve(result);
}
});
})
Note that the resolve and reject calls should not be scoped with Promise.. And you should have used an else to avoid calling resolve once you've called reject.
you have to do like this:
var promise1 = queryDatabaseAddToResult(connection, queries[0], result);
var promise2 = queryDatabaseAddToResult(connection, queries[1],result);
Promise.all([prromise1, promise2]).then(result => {
console.log(1);
}).catch(err => {
console.log(err);
});
return Promise.reject() //no need to add else part

Resources