How can I interact with a RDS MySQL instance with Node.js Lambda function? - mysql

I am attempting to access a MySQL database hosted on amazon RDS through amazon Lambda. I have .js files that I can run through cmd line on windows, but when I transfer to Lambda, I cannot connect to the database. I researched this issue thoroughly, and even after following this guide: Redstapler AWS, I receive a "process exited before completing request" error message.
My Code, copied from the above tutorial
var mysql = require('mysql');
var pool = mysql.createPool({
host: "",
user: "",
password: "",
database: ""
});
exports.handler = (event,context,callback) => {
context.callbackWaitFOrEmptyEventLoop = false;
pool.getConnection(function(err,connection){
if (err) throw err;
connection.query("SELECT * FROM testdata limit 10",
function(error,result,fields){
connection.release();
if (error) callback(error)
else callback(null,result)
});
});
};
Error Message received from Amazon Lambda
Response:
{
"errorMessage": "RequestId: b5151db1-6db8-11e8-8004-1b9e8072561c Process exited before completing request"
}
Request ID:
"b5151db1-6db8-11e8-8004-1b9e8072561c"
Function Logs:
START RequestId: b5151db1-6db8-11e8-8004-1b9e8072561c Version: $LATEST
2018-06-11T20:48:01.478Z b5151db1-6db8-11e8-8004-1b9e8072561c Error: Handshake inactivity timeout
at Handshake. (/var/task/node_modules/mysql/lib/protocol/Protocol.js:164:17)
at emitNone (events.js:86:13)
at Handshake.emit (events.js:185:7)
at Handshake._onTimeout (/var/task/node_modules/mysql/lib/protocol/sequences/Sequence.js:129:8)
at ontimeout (timers.js:386:14)
at tryOnTimeout (timers.js:250:5)
at Timer.listOnTimeout (timers.js:214:5)
--------------------
at Protocol._enqueue (/var/task/node_modules/mysql/lib/protocol/Protocol.js:145:48)
at Protocol.handshake (/var/task/node_modules/mysql/lib/protocol/Protocol.js:52:23)
at PoolConnection.connect (/var/task/node_modules/mysql/lib/Connection.js:130:18)
at Pool.getConnection (/var/task/node_modules/mysql/lib/Pool.js:48:16)
at exports.handler (/var/task/main.js:11:6)
END RequestId: b5151db1-6db8-11e8-8004-1b9e8072561c
REPORT RequestId: b5151db1-6db8-11e8-8004-1b9e8072561c Duration: 10074.63 ms Billed Duration: 10100 ms Memory Size: 1280 MB Max Memory Used: 27 MB
RequestId: b5151db1-6db8-11e8-8004-1b9e8072561c Process exited before completing request
This tutorial is highly rated and seems reputable, but I am unable to replicate its success. The error seems to imply that the connection.release is located in the wrong spot, or that I need to have another way of ending the connection and returning it to the pool.

Check to see that RDS instance security groups allow access from lambda IP address range (https://docs.aws.amazon.com/general/latest/gr/aws-ip-ranges.html) or place the lambda in VPC from which RDS instance is accessible.By default lambda is not in VPC...

Similar question:
updated : AWS Lambda is not able to connect to MySQL
Put console log statements to know if you are able to connect to RDS or not.
...
connection.release();
console.log(result);
if (error) callback(error)
...
Make sure you call pool.end() before calling callback function else lambda function execution won't be exited properly so you will get the timeout error.

Related

AWS Lambda/Nodejs is not executing mysql connection.query

I have a simple Lambda function to connect to MYSQL, but the connection.query is not executing.
Lambda has AWSLambdaVPCAccessExecutionRole access and it is part of the same VPC where RDS is deployed.
RDS security group is added to Lambda's configuration. log1 is the output that I always get. One time i got Log2. I am not sure what is going on.
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'xxxxxxxx.us-east-1.rds.amazonaws.com',
user : 'admin',
password : 'pass',
database : 'dbname'
});
console.log('CONNECTION ' + connection);
connection.connect();
console.log('2 ');
exports.handler = async (event,context,callback) => {
console.log('3 ');
context.callbackWaitsForEmptyEventLoop = false;
connection.query('SELECT emp_num from tag where emp_id=1', function (error, results, fields) {
console.log('2 ');
if (error) throw error;
else
callback(null, results)
//console.log('The solution is: ', results[0].tag_num);
});
connection.end();
};
Log1
START RequestId: 04c2d758-ac40-474f-ac55-045ccea8a9ff Version: $LATEST
2020-11-08T02:02:58.976Z 04c2d758-ac40-474f-ac55-045ccea8a9ff INFO 3
END RequestId: 04c2d758-ac40-474f-ac55-045ccea8a9ff REPORT RequestId:
04c2d758-ac40-474f-ac55-045ccea8a9ff Duration: 5.75 ms Billed
Duration: 100 ms Memory Size: 128 MB Max Memory Used: 20 MB
Log2
START RequestId: abeb6a6d-7480-4acc-91e2-5971e6fe74fe Version: $LATEST
2020-11-08T02:02:43.293Z abeb6a6d-7480-4acc-91e2-5971e6fe74fe INFO 3
2020-11-08T02:02:43.294Z abeb6a6d-7480-4acc-91e2-5971e6fe74fe INFO 2
2020-11-08T02:02:43.294Z abeb6a6d-7480-4acc-91e2-5971e6fe74fe ERROR Uncaught
Exception {"errorType":"Error","errorMessage":"Cannot enqueue Query
after invoking
quit.","code":"PROTOCOL_ENQUEUE_AFTER_QUIT","fatal":false,"stack":["Error:
Cannot enqueue Query after invoking quit."," at
Protocol._validateEnqueue
(/var/task/node_modules/mysql/lib/protocol/Protocol.js:215:16)","
at Protocol._enqueue
(/var/task/node_modules/mysql/lib/protocol/Protocol.js:138:13)","
at Connection.query
(/var/task/node_modules/mysql/lib/Connection.js:198:25)"," at
Runtime.exports.handler (/var/task/index.js:18:16)"," at
Runtime.handleOnce (/var/runtime/Runtime.js:66:25)"]} [ERROR]
[1604800963301] LAMBDA_RUNTIME Failed to post handler success
response. Http response code: 403. END RequestId:
abeb6a6d-7480-4acc-91e2-5971e6fe74fe REPORT RequestId:
abeb6a6d-7480-4acc-91e2-5971e6fe74fe Duration: 29.47 ms Billed
Duration: 100 ms Memory Size: 128 MB Max Memory Used: 20 MB
RequestId: abeb6a6d-7480-4acc-91e2-5971e6fe74fe Error: Runtime exited
with error: exit status 129 Runtime.ExitError
Your handle is defined to be async and you didn't await to the promise.
Possible solutions:
Add await call to your promise (i.e. await connection.query(...).promise())
Change the handler's signature to be non-async (i.e. exports.handler = (event,context,callback) => {...}) and then it will wait to the callback.
(Ugly workaround) Add context.callbackWaitsForEmptyEventLoop = true;, which tells AWS to wait for an empty event loop.
Disclosure: I work for Lumigo, a company that helps you to debug serverless applications.

Error: Cannot enqueue Query after fatal error. Expressjs. Mysql

I have my Express js connect to multiple dbs. Which works everytime I startup my app. But As soon as my connection to my database goes stale... the connection returns an error code of PROTOCOL_CONNECTION_LOST. Which is normal for a mysql when a connection is idle. My mysql server is deployed in AWS RDS which also works just fine.
The problem is, everytime my express app encounters the PROTOCOL_CONNECTION_LOST error, it should reconnect to the database, which in fact also works. BUUT when I try to make queries to my MYSQL db. It returns a Error: Cannot enqueue Query after fatal error. error. I've been dealing with this for a while, and my workaround is to restart the express app everytime. hope someone else has encountered this and could give an advice.
Here is my sample code for connecting to db:
var mysql = require('mysql');
var mysqlConn
// mysqlConn.connect();
function handleDisconnect() {
mysqlConn = mysql.createConnection({
host: 'aws_instance***',
user: '******',
password: '*****',
database: 'my_db',
multipleStatements: true
});
mysqlConn.connect(function (err) {
if (err) {
console.log('ERROR CONNECT admin:', err.code + '--' + err.address);
setTimeout(handleDisconnect, 2000);
} else {
console.log('Connected to DB')
}
});
mysqlConn.on('error', function (err) {
console.log('ERROR admin', err.code + '--' + err.address);
if (err.code === 'PROTOCOL_CONNECTION_LOST') { // Connection to the MySQL server is usually
console.log("Connection to db lost!")
handleDisconnect(); // lost due to either server restart, or a
} else {
console.log(err) // connnection idle timeout (the wait_timeout
throw err; // server variable configures this)
}
});
}
handleDisconnect();
module.exports = {
mysqlConn: mysqlConn,
};
Then here is my output logs as shown in my server logs.
ERROR db PROTOCOL_CONNECTION_LOST--undefined
Connection to db lost!
Connected to db
OPTIONS /verify-token/ 200 0.285 ms - 4
Error: Cannot enqueue Query after fatal error.
POST /verify-token/ 500 1.332 ms - 95
OPTIONS /auth/login 200 0.793 ms - 4
Error: Cannot enqueue Query after fatal error.
POST /login 500 1.564 ms - 58
OPTIONS /login 200 0.687 ms - 4
Error: Cannot enqueue Query after fatal error.
POST /login 500 1.467 ms - 58
While there are workarounds, they apparently don't work for everyone. The suggestion in the documentation is to use connection pooling instead of manually managing individual connections.

Simple React with mySql fails to read table records

I created a React project by entering the following command prompt commands
mkdir mysql-test && cd mysql-test
npm init –y
npm install mysql –save
Then I created a file called app.js and I put in the following code:
// app.js
const mysql = require('mysql');
// First you need to create a connection to the db
const con = mysql.createConnection({
host: 'rds-mysql-wmcw.cgz0te1dlkah.us-east-1.rds.amazonaws.com',
user: 'masterUsername',
password: 'masterPassword',
database : 'db_wmcw'
});
//try to connect to the mySql database. If an error occurs, display an
error message on the console
con.connect((err) => {
if(err){
console.log('Error connecting to Db');
return;
}
//a connection has been established to the database. Now, run a query against the table 'homepage'
//to retrieve each row and all columns of the table
console.log('Connection established');
con.query('SELECT * FROM homepage', (err,rows) => {
//if an error occurs when reading the data from the table, display the error on the console
if(err) {
console.log(err);
return;
}
//data has been retrieved from the table. display the data to the console
console.log('Data received from Db:\n');
console.log(rows);
});
});
con.end((err) => {
// The connection is terminated gracefully
// Ensures all previously enqueued queries are still
// before sending a COM_QUIT packet to the MySQL server.
});
Before I added the con.query command, when I type in app.js at the command prompt, the response back is Connection established. So I know that I am connecting to the mySql database. When I include the con.query command, and I type in app.js at the command prompt, I get the following error:
Connection established
{ Error: Cannot enqueue Query after invoking quit.
at Protocol._validateEnqueue (C:\jrs\codercamp\mysql-test\node_modules\mysql\lib\protocol\Protocol.js:203:16)
at Protocol._enqueue (C:\jrs\codercamp\mysql-test\node_modules\mysql\lib\protocol\Protocol.js:138:13)
at Connection.query (C:\jrs\codercamp\mysql-test\node_modules\mysql\lib\Connection.js:200:25)
at Handshake.con.connect (C:\jrs\codercamp\mysql-test\app.js:21:7)
at Handshake. (C:\jrs\codercamp\mysql-test\node_modules\mysql\lib\Connection.js:502:10)
at Handshake._callback (C:\jrs\codercamp\mysql-test\node_modules\mysql\lib\Connection.js:468:16)
at Handshake.Sequence.end (C:\jrs\codercamp\mysql-test\node_modules\mysql\lib\protocol\sequences\Sequence.js:83:24)
at Handshake.Sequence.OkPacket (C:\jrs\codercamp\mysql-test\node_modules\mysql\lib\protocol\sequences\Sequence.js:92:8)
at Protocol._parsePacket (C:\jrs\codercamp\mysql-test\node_modules\mysql\lib\protocol\Protocol.js:278:23)
at Parser.write (C:\jrs\codercamp\mysql-test\node_modules\mysql\lib\protocol\Parser.js:76:12) code: 'PROTOCOL_ENQUEUE_AFTER_QUIT', fatal: false }
Right at the top of the error it states Cannot enqueue Query after invoking quit. I don't understand why the system thinks I am executing the query after invoking quit. I am not invoking quit unless that is what happens when I execute con.end but con.end is the last statement to execute. It is way after the query call.
Any assistance is greatly appreciated.
Thank you.
PS - I have included the host name, user ID, password, and database name to make debugging easier. There is no real important data in the database
Okay, so the alternative solution would be uninstall mysql package and change with mysql2 package instead. As the author said:
MySQL2 is mostly API compatible with mysqljs and supports majority of features
This answer is for the questioner's comment on his post
If you really wanna reassign the one row of data, you can do:
const { product_detail, product_description } = results[0];
That's basic syntax :D (ES6 maybe)

Cannot connect to live database in Nodejs Openshift Application

I have no trouble connecting to the live database locally using port forwarding, but when we go to connect from the openshift gear, we get errors. Let me begin with the code:
Here is the connection variable
var connectionpool = mysql.createPool({
host : process.env.OPENSHIFT_MYSQL_DB_HOST,
port : process.env.OPENSHIFT_MYSQL_DB_PORT,
user : process.env.OPENSHIFT_MYSQL_DB_USERNAME,
password : process.env.OPENSHIFT_MYSQL_DB_PASSWORD,
database : 'stembuds',
socket : process.env.OPENSHIFT_MYSQL_DB_SOCKET
});
Here is an example of a query:
app.get('/answerDB/:course?/:answerID?', function(req, res){
var course = req.param('course');
var answerID = req.param('answerID');
connectionpool.getConnection(function(err, connection){
if(err){
console.error('CONNECTION error: ',err);
res.statusCode = 503;
res.send({
result: 'error',
err: err.code
});
}
if (course === undefined && answerID === undefined) {
connection.query('SELECT * FROM questions WHERE counter = 0', function(err, rows, fields){
if (err) {
console.error(err);
res.statusCode = 500;
res.send({
result: 'error',
err: err.code
});
}
for(var i in rows){
var newCourse = rows[i].course;
newCourse = courses[newCourse];
rows[i].course = newCourse;
}
res.send(rows);
connection.release();
});
}
Here are some errors we receive.
First is an error in the console of Chrome:
GET http://**.rhcloud.com/answerDB 503 (Service Temporarily Unavailable)
But sometimes we get a proxy error:
GET http://**.rhcloud.com/exploreDB 502 (Proxy Error)
Additionally, I have been running the command rhc tail -a nodejs and here is the error I am receiving
CONNECTION error: { [Error: ER_ACCESS_DENIED_ERROR: Access denied for user 'adminMYXaSuf'#'127.11.28.130' (using password: YES)]
code: 'ER_ACCESS_DENIED_ERROR',
errno: 1045,
sqlState: '28000',
fatal: true }
TypeError: Cannot call method 'query' of undefined
at /var/lib/openshift/5303aee55973ca4092000084/app-root/runtime/repo/routes/site.js:172:15
at Pool.<anonymous> (/var/lib/openshift/5303aee55973ca4092000084/app- root/runtime/repo/node_modules/mysql/lib/Pool.js:49:16)
at Handshake.Sequence.end (/var/lib/openshift/5303aee55973ca4092000084/app-root/runtime/repo/node_modules/mysql/lib/protocol/sequences/Sequence.js:78:24)
at Handshake.ErrorPacket (/var/lib/openshift/5303aee55973ca4092000084/app-root/runtime/repo/node_modules/mysql/lib/protocol/sequences/Handshake.js:93:8)
at Protocol._parsePacket (/var/lib/openshift/5303aee55973ca4092000084/app-root/runtime/repo/node_modules/mysql/lib/protocol/Protocol.js:202:24)
at Parser.write (/var/lib/openshift/5303aee55973ca4092000084/app-root/runtime/repo/node_modules/mysql/lib/protocol/Parser.js:62:12)
at Protocol.write (/var/lib/openshift/5303aee55973ca4092000084/app-root/runtime/repo/node_modules/mysql/lib/protocol/Protocol.js:37:16)
at Socket.<anonymous> (/var/lib/openshift/5303aee55973ca4092000084/app-root/runtime/repo/node_modules/mysql/lib/Connection.js:72:28)
at Socket.EventEmitter.emit (events.js:95:17)
at Socket.<anonymous> (_stream_readable.js:720:14)
Now it says cannot call method query of undefined. We thought that was strange, so we changed 'connection.query' to 'connectionpool.query' and it then told us that it cannot call method release of undefined. So we changed 'connection.release()' to 'connectionpool.release()' and it told us that the object # has no method release. So I am taking that part of the error with a grain of salt.
We have no idea why it wont connect. Any information would be greatly appreciated - Thanks.
If your application code works locally while connecting to your remote OpenShift-hosted DB (using rhc port-forward), then I would suspect that your app may have some undocumented dependencies.
It could be that you've installed something locally (or globally) in your dev environment, without including that dep in your app's package.json file.
Make sure that everything your app needs in order to run in a fresh environment is included in your app's package.json file before pushing it to OpenShift.
npm install my_dependency --save
I've written up some additional notes that might be useful for testing locally with a port-forwarded connection to an OpenShift-hosted DB: https://www.openshift.com/blogs/set-up-local-access-to-openshift-hosted-services-with-port-forwarding
Did you create that database name? It should be the name of your application. You can use the OPENSHIFT_APP_NAME environment variable for your database name. Can you ssh into your gear and connect to mysql without any issues? Also, are you trying to connect to the database on your openshift gear from your local machine or from your openshift gear?

node.js mysql socket error after stress test

I use node.js, an asynchronous event base server with mysql module to select 122 rows of records from the database.
I ran a simple stress test using the command below:
ab -n 10 -c 2 http://localhost:8000/
the node.js finish the process, but mysql is still running, until it hits an error:
throw new Error('Socket is not writable');
^
Error: Socket is not writable
at Socket._writeOut (net.js:391:11)
at Socket.write (net.js:377:17)
at Client.write (/home/kelvin/node_modules/mysql/lib/client.js:142:16)
at Object.end [as fn] (/home/kelvin/node_modules/mysql/lib/client.js:240:10)
at Client._dequeue (/home/kelvin/node_modules/mysql/lib/client.js:274:18)
at Object.end [as fn] (/home/kelvin/node_modules/mysql/lib/client.js:247:10)
at Client._dequeue (/home/kelvin/node_modules/mysql/lib/client.js:274:18)
at Object.end [as fn] (/home/kelvin/node_modules/mysql/lib/client.js:247:10)
at Client._dequeue (/home/kelvin/node_modules/mysql/lib/client.js:274:18)
at Object.end [as fn] (/home/kelvin/node_modules/mysql/lib/client.js:247:10)
Now whenever I run the test again, I get the same error.
Is MySQL a good solution to use with Node.js or is it how I code?
Some node.js code:
var server = http.createServer(function (request, response) {
response.writeHead(200, {"Content-Type": "text/plain"});
client.query('USE ' + db);
client.query('SELECT * FROM ' + tbl,
function selectDb(err, results, fields) {
if (err) {
throw err;
}
console.log(results);
client.end();
}
);
response.end("END RESULT");
});
You share one mysql connection object for every connection: When two clients request a page simultanously you maybe destroy the internal state of your mysql library while it is not intended to send a new query when another query is right now executing.
Use one mysql connection for every request, you can use node-pool if you want pooling for mysql connections.