The problem has been solved, but I'd like to leave this question with a deeper impression. Thanks for everyone!
update
I found something wrong in /src/mysql/index.js, this code
/* this is wrong */
MySqlConnection.connect((error) => {
/* old code */
throw new Error(error.message);
/* new code */
error && new Error(error.message);
});
After modification, i'm connected to MySQL.But i still can't get correct return , i got nudefined...
I tried using node to connect MySQL and operate it, but i failed and get no error message.
I used koa2 and mysql from npm packages.
"koa2": "^2.0.0-alpha.7",
"mysql": "^2.17.1",
My MySQL version is 8.0
I encapsulates a function to connect mysql, i'm sure that MySQL's configuration is useless.
/* /src/mysql/index.js */
const MySqlConnection = require("./mysql.index");
/**
* connnect mysql
* #param {string} sqlStatement sql statement
* #param {object} params some required parameters
* #param {function} callback if success
*/
const MySqlOperator = (sqlStatement, params, callback) => {
MySqlConnection.connect((error) => {
throw new Error(error.message);
});
MySqlConnection.query(sqlStatement, params, (error, result, fieldValues) => {
try {
callback && callback(result, fieldValues);
} catch {
throw new Error(error.message);
}
});
MySqlConnection.end();
MySqlConnection.destroy();
};
module.exports = MySqlOperator;
and i use it like that
const MySqlOperator = require("./src/mysql/MySql");
// These three fields are all char types
const sql = "INSERT INTO users(userUuid, userName, userPwd) values(1111,2222,3333);";
MySqlOperator(sql, {}, (error, result, fliedValues) => {
if (error) {
console.log(error.message);
} else {
/* here is undefined... */
console.log(result, fliedValues);
}
});
App.listen(ServerPort, () => {
// eslint-disable-next-line no-undef
console.log("start success");
});
After I executed node index.js, node told me that he had successfully started, and terminal output start success, but the MySQL plug-in did not work and there was no error message.What can I do to successfully insert this data into MySQL?
Firstly, you say this:
// These three fields are all char types
const sql = "INSERT INTO users(userUuid, userName, userPwd) values(1111,2222,3333);";
So I would advise you to respect types and modified this as:
const sql = "INSERT INTO users(userUuid, userName, userPwd) values('1111','2222','3333');";
And I think you have also a mistake in this part of /src/mysql/index.js file:
try {
callback && callback(result, fieldValues);
} catch {
throw new Error(error.message);
}
Your original callback function accepts three arguments: (error, result, fliedValues) and you pass there your DB result as an error and because I suppose your query result will be without error (as undefined), then console.log(result, fliedValues); writes undefined.
Related
I am trying to connect an external (not AWS) MySql server from an AWS Lambda function written in Node.js using nodejs14.x environment, but the connect() callback is not called.
I am been struggling with this problem since days, there are a lot of references to similar issues but I really tried all possible permutations of solutions I found.
I am deploying with SAM and testing both on local machine and on real AWS.
Here is the sample code of the lambda helper
const mysql = require('mysql');
exports.helloFromLambdaHandler = async () => {
const message = 'Hello from Lambda!';
console.info(`${message}`);
var sql = "SELECT 1+? AS sum";
var values = [1];
console.log("Doing createConnection");
const connection = mysql.createConnection({
/* my connection data */
});
console.log("Doing connect");
connection.connect( (err) => {
console.log("Inside connection callback");
console.log('connected as id ' + connection.threadId);
if(!err) {
console.log("DB connected, thread id is " + connection.threadId);
console.log("Doing query");
connection.query(sql, values, (err, result, values) => {
console.log("Inside query callback");
if(!err) {
console.log("Query ok!");
console.log(result);
connection.end();
} else {
console.log("Error executing query: " + err.message);
}
});
} else {
console.log("Error connecting db: "+ err.message);
}
});
console.log ("Returning...");
return message;
}
The log is
Hello from Lambda!
Doing createConnection
Doing connect
Returning...
The expected behaviour is that after "Returning..." I should see the log "Inside connection callback" then "Inside query callback" and then "Query ok!".
Instead the callback of connect() appears not invoked.
I know that I can call query() directly skipping connect() but also doing so I encounter same issue.
Any clue?
Thank you!
SOLUTION
As suggested by the accepted answer, returning a promise is the solution to let Node complete all the queue. Unfortunately it's not possible to complete the Lambda and leave it running in background in a safe manner, for what I understand.
I am investigating alternative solutions such as:
mysql2 library which supports promises natively
serverless-mysql npm package which handles shared db connections
Below the running demo code
const mysql = require('mysql');
exports.helloFromLambdaHandler = async (event, context) => {
const message = 'Hello from Lambda!';
console.info(`${message}`);
var sql = "SELECT 1+? AS sum";
var values = [1];
console.log("Doing createConnection");
const connection = mysql.createConnection({
/* my connection data */
});
console.log("Doing query");
const promise = new Promise( (resolve, reject) => {
connection.query(sql, values, (err, result, values) => {
console.log("Inside query callback");
if(!err) {
console.log("Query ok!");
console.log(result);
connection.end();
resolve(message);
} else {
console.log("Error executing query: " + err.message);
reject(err);
}
});
});
console.log ("Returning...");
return promise;
}
You are using async handler, thus your function probably completes before your connect() has a chance to execute.
To try to overcome the issue, you can use Promise as shown in AWS docs.
I am working on a discord.js bot, and I'm storing a bunch of information on various servers in a database. The problem is, that the code doesn't wait for the database to return the results. In the current situation, I'm trying to check if the server specific prefix checks out.
I tried using async and await at various places, but those didn't work. If I could, I'd rather not use .then(), because I don't really want to put all the commands inside a .then().
const { Client, Attachment, RichEmbed } = require('discord.js');
const client = new Client();
const mysql = require("mysql");
const config = require("./config.json")
var con = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: 'botdb'
})
client.on("ready", () => {
console.log("I'm ready")
})
client.on("message", message => {
if (message.author.bot) return;
if (message.channel.type === 'dm') return;
let msg = message.content.split(" ");
let command = msg[0];
let prefix;
con.query(`SELECT * FROM serversettings WHERE ServerID = ${message.guild.id}`, (err, rows) => {
if (err) throw err;
prefix = rows[0].Prefix;
console.log(prefix)
})
console.log(`Prefix: ${prefix}, Command: ${command}`)
if (command === `${prefix}examplecommand`) {
//Do something
}
//Other code that uses prefix and command
}
It should log the prefix first, and then the Prefix: ${prefix}, Command: ${command} part, but it does it the other way around, so the examplecommand doesn't work.
Your result is caused by the fact that what's outside your query callback is executed immediately after the call. Keep in mind the mysql module is callback-based.
Possible Solutions
Place the code inside the callback so it's executed when the query is completed.
Wrap the query in a promise and await it.
function getGuild(guildID) {
return new Promise((resolve, reject) => {
con.query(`SELECT * FROM serversettings WHERE ServerID = '${guildID}', (err, rows) => {
if (err) return reject(err);
resolve(rows);
});
});
}
const [guild] = await getGuild(message.guild.id) // destructuring 'rows' array
.catch(console.error);
console.log(guild.prefix);
Use a Promise-based version of a MySQL wrapper, like promise-mysql. You could use it the same way as the code above, without worrying about coding your own Promises.
const [guild] = await con.query(`SELECT * FROM serversettings WHERE serverID = '${message.guild.id}'`)
.catch(console.error);
console.log(guild.prefix);
I am trying to create an authentication system using Hapi and MySQL, I am testing it using postman, and I am also logging the output of the query on the terminal console.
The thing is, the console outputs the query successfully, however, postman returns An internal server error occurred, and the console doesn't return any error. I'll send the handler function of my route, found below:
handler: async function(req, h) {
const pass = req.payload.password;
const username = req.payload.username;
var res;
res = await con.query("SELECT * FROM `Person` WHERE `Username` = ?", username,
(err, rows, fields) => {
if(err) {
console.log("Query Error: ", err, "!");
return err;
} else {
console.log("Query Successful!");
const person = JSON.parse(JSON.stringify(rows[0]));
console.log(person);
if(person != null) {
//const hashedPass = crypto.pbkdf2Sync(req.payload.password, person.salt, 10000, 64, 'sha1').toString('base64');
if(pass != person.Password) {
return boom.badRequest('Invalid username/password.');
} else {
var token = jwt.sign(person, config.jwtKey);
person.token = token;
return person;
}
} else {
return boom.badRequest('Invalid username/password. Failed.');
}
}
}
);
return res;
}
I solved the problem by adding another node_module that encapsulates the regular mysql node module functions with promises.
The package is called promise-mysql.
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)
I am very new to Node.js development and I am working on an app that requires me to pull users from a mysql database. I am using the promise-mysql library to query a mysql database. I am trying to use a connection pool like this:
var pool = mysql.createPool({
host: hgh.host,
user: hgh.user,
password: hgh.pw,
database: hgh.name,
connectionLimit: 10
});
As a global variable in my module.
I then have the above function to return a connection from the pool.
function connect() {
return pool.getConnection().then(function(connection) {
return connection
}).catch(function(error) {
console.log("Connect failed");
throw ErrorModel.generateErrorObject(error, 500);
});
}
Below is a function I am using to query the database with:
function getUser(username) {
var sql_query = `SELECT * FROM userstable WHERE userName = ` + `'` + username + `'`;
return connect().then(function(conn) {
return conn.query(sql_query).then(function(rows) {
console.log("HGH getUser Then");
console.log(pool);
conn.release();
return rows;
});
}).catch(function(error) {
console.log("HGH getUser Catch");
console.log(error);
throw ErrorModel.generateErrorObject(error, 500);
});
}
I am getting this issue:
conn.release is not a function when trying to release my current connection into the pool. Is my logic wrong here? My goal is to have a pool with a bunch of connections (up to a certain number) and if a user needs to query, the getConnection() function just grabs them either a free connection from the pool, or creates them one. Problem is I cannot for the life of me release it back to the pool as free..Every time I make a request with conn.end() instead of release the connection remains in the _allConnections array of the pool when I console it out, and there are absolutely no connections in the _freeConnections array.
Anyone know how I can make connections free again??
Looking at the module's code I found the function for releasing a connection from a pool:
pool.prototype.releaseConnection = function releaseConnection(connection) {
//Use the underlying connection from the mysql-module here:
return this.pool.releaseConnection(connection.connection);
};
So if all of these functions live in the same file you could do the following in the getUser function:
replace
conn.release();
with
pool.releaseConnection(conn);
Looking at the code, promise-mysql wraps the original connection object, which doesn't expose the release method. However, the original is exposed as a property called connection, so this works:
conn.connection.release();
A few random thoughts:
You should probably escape your query input:
var sql_query = `SELECT * FROM userstable WHERE userName = ${ pool.escape(username) }`;
Your code doesn't release connections when an error occurs (because the code in the .then() callback wouldn't get called); it's better to use .finally() to do the releasing, as that will get called for both resolved and rejected cases:
function connect() {
var conn = null;
return pool.getConnection().then(function(connection) {
conn = connection;
return connection;
}).catch(function(error) {
console.log("Connect failed", error);
}).finally(function() {
if (conn) {
conn.connection.release();
}
});
}