Azure function query to MySQL DB not waiting for query result - mysql

I have an Azure Function that connects to a MySQL DB outside of Azure. The DB connection is working, I am able to run INSERT queries without issue. The problem is that when I try to do a SELECT query and try to print the returned DB records to the console it shows as undefined. Below is the relevant code:
const mysql = require('mysql');
module.exports = async function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
var connection = mysql.createConnection({
...
});
connection.connect();
let result;
const selectQuery = `SELECT * FROM emails WHERE email_address = 'tester#email.com'`;
await connection.query(selectQuery, async function (error, results, fields) {
if (error) throw error;
// This log doesn't work, it shows an error (see below code)
context.log(`Result: ${results}`)
result = results;
});
// Logging result here shows as undefined.
context.log(result);
connection.end();
context.log('Disconnected.');
The log inside the connection.query call results in this warning: Warning: Unexpected call to 'log' on the context object after function execution has completed. Please check for asynchronous calls that are not awaited or calls to 'done' made before function execution completes.
Then I try to save the result to a variable and log it after the query function, it returns as undefined. My guess is that I'm using await wrong for this, but I can't figure out how to get it right.

Warning: Unexpected call to 'log' on the context
object after function execution has completed.
Please check for asynchronous calls that are not
awaited or calls to 'done' made before function
execution completes.
The reason for the above warning and why you get undefined ? is because when assigning the variable, the statements of console logging the variable are executed before the connection.query can finish execution.
Now the work around for this would be that all the processing related to the variable i.e., result of the query must be done inside the call back function itself.
Here I have a NodeJS script which will run the query and console.log the result.
var mysql = require('mysql');
var connection = mysql.createConnection({
...
});
connection.connect();
connection.query('SELECT L FROM NEWTABLE WHERE P=1 ', function (error, results, fields) {
console.log("Logging inside the callback function");
if (error) throw error;
console.log(results);
});
connection.end();
output:
you can also set the context.res for your httptriggred function inside the callback function.

Related

Testing an AWS Lambda function

I need to create a lambda function to act as the middleman between a mobile Java app and an AWS RDS MySQL database. The idea is to submit queries from the mobile app and then send them off to the lambda function, which will then return the query. I have a basic MySQL query set up in my AWS lambda:
var mysql = require('mysql');
var config = require('./config.json');
var pool = mysql.createPool({
host : config.dbhost,
user : config.dbuser,
password : config.dbpassword,
database : config.dbname
});
exports.handler = (event, context, callback) -> {
context.callbackWaitsForEmptyEventLoop = false;
pool.getConnection(function(err, connection) {
if (err) throw err; // not connected!
// Use the connection
connection.query('select Album from record', function (error, results, fields) {
// When done with the connection, release it.
connection.release();
// Handle error after the release.
if (error) callback(error);
else callback(null, results[0].Album);
// Don't use the connection here, it has been returned to the pool.
});
});
};
And all that I am currently trying to do is get this code to run and output what the query will return. I've seen tutorials where people seem to just click test and have the code run, but it keeps asking me to create a test, and I'm not sure what exactly I would need to do to test this function.
EDIT: I realized I was missing a small change in my lambda uploaded code, but I am now getting an error on line 10 saying there is an unexpected token >.
I'm not sure what's wrong here, as the tutorial I watched seems to have the same exact thing.
Since you're not passing in any parameters through the context, you can just create a test with the defaults or an empty object {}, and click Test in the console. It will invoke your Lambda function as if it had been called from your mobile app, and you can debug from there.

AWS Step Function's action startExecution doesn't start on mysql .query() callback

I want to be able to startExecution of a step-function with the result of a mysql query but I can't get it to work.
I'm using AWS-SDK on lambda running nodejs 4.3 and mysql package.
I managed easily to start an execution of the step-function using AWS-SDK and I wrapped it in a function:
function startExecution(){
var AWS = require('aws-sdk');
var stepfunctions = new AWS.StepFunctions();
var params = {
stateMachineArn: 'arn:aws:states:us-east-1:453687599700:stateMachine:Temp',
input: '{"OrderID":266}',
name: '00002'
};
stepfunctions.startExecution(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
}
Calling startExecution() under
exports.handler = (event, context, callback) => {
works perfectly.
However, calling the same startExecution() inside the callback function of mysql's connection.query doesn't work:
connection.query('SELECT * FROM `books` WHERE `author` = "David"', function (error, results, fields) {
startExecution(); //doesn't work :(
});
Tracking the code using console.log() reveals that the line:
stepfunctions.startExecution(params, function(err, data) {
seems like it's being skipped.
Your help will be highly appreciated!
Thanks so much..
Probably your lambda completes before startExecution completes.
Try this syntax instead:
const executeResult = await stepfunctions.startExecution(params).promise()
console.log('executeResult: ', executeResult)

Return data from database.query() using sailsjs

I am trying to build an api using sailsjs that calls stored procedures of a MYSQL database. I decided to decouple the query by adding it to a service so that others functions might be able to call them and use them. Below is what I came up with.
under /api/controller/MySqlController
getAllUsers: function (req, res) {
MySqlSpService.spGetAllUsers(function(err, result){
if(err) return res.serverError(err);
return res.ok(result[1]);
});
},
under /api/services/MYSQLService
var MySqlSpService= {
spGetAllUsers: function(callback) {
Database.query('call userDb.sp_get_all_users(#message, #mystatus)', function (err, results) {
callback(err, results);
}); // end query
}
module.exports = MySqlSpService;
When I hit the api the data is displayed exactly how I thought it would be. But the problem is that when I try to call the spGetAllUsers service and assign to a variable, I get a undefined value.
Like this:
var users = MySqlSpService.spGetAllUsers(function(err, result){
if(err) return res.serverError(err);
return result[1];
});
I believe the problem is with the callbacks but I am not sure how to retrieve the data from the query. I have searched for an answer but I can't seem to find the right search terms that match my problem. Any help would be greatly appreciated Thanks in advance.
Indeed, your problem is about callback and asynchronous code.
The MySqlSpService.spGetAllUsers() function does not return anything, there is no return statement in this method. But it executes a callback function where you have the opportunity to execute code that depends on the SQL query result.
You have to write your code like this because the database query is executed asynchronously.
console.log('This is executed first');
MySqlSpService.spGetAllUsers(function(err, result){
console.log('This is executed when the result of the database query is received');
if(err) return res.serverError(err);
users = result[1];
/**
* Here you can access to the "users" data
* and execute code depending on it
*/
});
console.log('This is executed in second and it is not possible to know the result of the query yet');
Tools like async can help you to organize your asynchronous code. By default, async is available globally in sails.js.

Node Mysql Cannot Enqueue a query after calling quit

where do i close the mysql connection?
I need to run queries in sequence. I am writing code that looks like this at present:
var sqlFindMobile = "select * from user_mobiles where mobile=?";
var sqlNewUser = "insert into users (password) values (?)";
//var sqlUserId = "select last_insert_id() as user_id";
var sqlNewMobile = "insert into user_mobiles (user_id, mobile) values (?,?)";
connection.connect(function(err){});
var query = connection.query(sqlFindMobile, [req.body.mobile], function(err, results) {
if(err) throw err;
console.log("mobile query");
if(results.length==0) {
var query = connection.query(sqlNewUser, [req.body.password], function(err, results) {
if(err) throw err;
console.log("added user");
var user_id = results.insertId;
var query = connection.query(sqlNewMobile, [user_id, req.body.mobile], function(err, results) {
if(err) throw err;
console.log("added mobile");
//connection.end();
});
});
}
});
//connection.end();
(I am a beginner with node, npm-express and npm-mysql. I have tried searching SO for "express mysql cannot enqueue" to find related questions and have not found them.)
I fixed this problem use this method:
connection.end() in your connection.query function
The fixed code is here
If you're using the node-mysql module by felixge then you can call connection.end() at any point after you've made all of the connection.query() calls, since it will wait for all of the queries to finish before it terminates the connection.
See the example here for more information.
If you're wanting to run lots of queries in series, you should look into the async module, it's great for dealing with a series of asynchronous functions (i.e. those that have a callback).
Maybe the problem is that the mySQL query is executed after the connection is already closed, due to the asynchronous nature of Node. Try using this code to call connection.end() right before the thread exits:
function exitHandler(options, err) {
connection.end();
if (options.cleanup)
console.log('clean');
if (err)
console.log(err.stack);
if (options.exit)
process.exit();
}
//do something when app is closing
process.on('exit', exitHandler.bind(null, {cleanup: true}));
Code adapted from #Emil Condrea, doing a cleanup action just before node.js exits
In my case connection.end was being called in a spot that was hard to notice, so an errant call to connection.end could be the problem with this error

NodeJS mysql query returns empty result

i'm new to NodeJS (duh!).
I know it executes functions asynchronous but I still cannot see what causes this phenomenon:
I am using the express and mysql modules and trying to execute an SQL query based on request parameters. It is supposed to be a simple validation API feature where the server is going to lookup a user in a database by listening on a specific URL for two request parameters (user and passwd).
The problem is that the SQL query always returns an empty object as result when I do this using the request parameters in the query.
However, if i hard code the query and run it outside the app.get(...) I get the desired result! But I need this to work on demand by request...
(I'm not intending to use GET-request later on, this example is for debugging purposes :))
What am i doing wrong here?
Here's my code:
// Server and Mysql setup here
var app = require('express').createServer(),
SERVER_PORT = 8080;
var Client = require('mysql').Client,
client = new Client(),
...
// User, password and database setup here, cropped out from this example //
// ...
function validateUser(user, passwd, callback) {
client.query('SELECT date FROM '+CUSTOMERS_TABLE+' WHERE email="'+user+'" AND passwd="'+passwd+'";',
function selectCb(err, results, fields) {
if (err) {
throw err;
}
console.log(fields);
callback(results);
});
}
app.get('/', function(req, res){
var url_parts = url.parse(req.url, true);
var query = url_parts.query;
if((typeof query[REQ_PARAM_USER] != 'undefined' && typeof query[REQ_PARAM_PASSWD] != 'undefined')
&& (query[REQ_PARAM_USER] != '' && query[REQ_PARAM_PASSWD] != '')) {
validateUser(REQ_PARAM_USER, REQ_PARAM_PASSWD, function(results) {
console.log(results);
});
}
res.end("End")
});
app.listen(SERVER_PORT);
console.log('Server running at port '+SERVER_PORT);
Oh, and by the way, console.log(fields) outputs the correct fields! But why not the results?
You are passing the wrong parameters to validateUser:
validateUser(REQ_PARAM_USER, REQ_PARAM_PASSWD, // ...
What you really want:
validateUser(query[REQ_PARAM_USER], query[REQ_PARAM_PASSWD], // ...
Edit: A few other issues with your code:
You don't have to parse the url. Express does this for you, and the query is available as req.query.
You shouldn't throw in asynchronous code. It will give unexpected results. Instead, stick to the nodejs paradigm of passing (err, results) to all callbacks, and do proper error checking where you can -- i.e., in your verifyUser, pass along the error with the callback and check for errors in your get handler. Either res.send(500) (or something) when you get an error, or pass it along to the express error handler by calling next(err).
validateUser(query[REQ_PARAM_USER], query[REQ_PARAM_PASSWD], function(err, results) {
if(err) {
console.error(err);
res.send(500);
} else {
console.log(results);
res.send(results);
}
});
Never pass query parameters directly to something like an SQL query. Instead, use parameters for your SQL query:
client.query('SELECT date FROM '+CUSTOMERS_TABLE+' WHERE email=? AND passwd=?', [user, passwd], // ...