Lambda AWS not calling node mysql callbacks - mysql

I am trying to process bounces sent from Amazon's Simple Email Service via their Simple Notification Service vi a Lambda on AWS.
I'm running the following script:
var aws = require('aws-sdk');
var mysql = require('mysql');
Processor = {};
Processor.initializeConnection = function() {
console.log('Connecting to database');
Processor.connection = mysql.createConnection({
host : 'MYHOST',
user : 'MYUSER',
password : 'PASSWORD',
database : 'DATABASE'
});
console.log('Connection configured');
Processor.connection.connect(function(err) {
console.log('****');
console.log(err);
if (err != null) {
console.log('Could not connect to database');
return false;
} else {
console.log('Successfully connected to database');
return true;
}
});
console.log('Should not get here');
};
exports.handler = function(event,context){
console.log('Received event:');
var message = event.Records[0].Sns.Message;
// Get the object from the event and show its content type
if(Processor.initializeConnection()) {
context.fail('Database connection failed');
return;
}
context.succeed(message);
};
I upload this script as index.js along with node_modules containing the node mysql module all as a zip file.
I get the following output from Amazon when this is run:
START RequestId: 378b8a8c-30d4-11e5-9db4-9b9537e3f53d
2015-07-23T00:46:13.159Z 378b8a8c-30d4-11e5-9db4-9b9537e3f53d Received event:
2015-07-23T00:46:13.160Z 378b8a8c-30d4-11e5-9db4-9b9537e3f53d Connecting to database
2015-07-23T00:46:14.035Z 378b8a8c-30d4-11e5-9db4-9b9537e3f53d Connection configured
2015-07-23T00:46:14.095Z 378b8a8c-30d4-11e5-9db4-9b9537e3f53d Should not get here
END RequestId: 378b8a8c-30d4-11e5-9db4-9b9537e3f53d
REPORT RequestId: 378b8a8c-30d4-11e5-9db4-9b9537e3f53d Duration: 937.51 ms Billed Duration: 1000 ms Memory Size: 128 MB Max Memory Used: 14 MB
None of the code inside the connect fallback is run. I'm expecting it to report a connection failure as I'm not using valid credentials.
If I run a version of the code locally under nodejs the connect callback does fire. It just doesn't fire under Lambda.

Due to the asynchronous nature of node.js, your code might be exiting as a result of context.succeed() before all of your functions are executed.
See:
Async AWS Lambda not executed if caller returns too early
Why is this HTTP request not working on AWS Lambda?

Related

Amazon RDS load balancing not working with mysql.createPool in nodejs

I have implemented load balancing in read database connection like when read db load increased to 60% it will initiate a new read database for balancing load on database but
When I see from AWS developer console dashboard all API calls It will initate new read database instance but most of the API's calls load took placed on database 1 upto 90 percent but like 10 req /sec and on read DB instance 2 1 to 5% database is used like 1req /sec
it should divided API request on both database equaly but It wont work
This issue is because mysql.createPool will not close connection from database 1 (createPool will reuse its opened connections) so that other API calls can move to second database instance.
To solve this problem I had changed mysql.createPool with mysql.createConnection on Each API calls
I had created 2 middleware
1-for createConnection
2-for connection.end()
whenever a request comes in middleware 1 calls and create new connection and on request finish middleware 2 will call which will end the connection. this solution has solved my problem of load balancing but a new issue takes place I have face to many database connection issues with this method
does anyone have a proper solution who has faced this issue or can help?
Sample Code :
var readDB = mysql.createConnection({
database: process.env.READ_DB_DATABASE,
host: process.env.READ_DB_HOST,
user: process.env.READ_DB_DB_USER,
password: process.env.READ_DB_DB_PASSWORD,
charset: "utf8mb4"
});
utils.js
async onFinish(req, res, next) {
return new Promise(async (resolve, reject) => {
try {
let readDB = req.readDB;
const dbEnd = util.promisify(readDB.end).bind(readDB);
const response = await dbEnd();
resolve(response);
} catch (error) {
reject(error);
}
});
}
app.js
/**
* middleware for create connection and end connection on finish
*/
app.use(async (req, res, next) => {
try {
const readDB = await utils.readDBCreateConnection();
req.readDB = readDB;
res.on("finish", function () {
console.log("onFinish called");
utils.onFinish(req, res, next);
});
next();
} catch (error) {
res.status(error.status || 500).send({
code: 500,
message: error.message || `Internal Server Error`,
});
}
});
/**
* Code to initialice routing
*/
require("./modules/v2-routes")(app); // v2 app routes

Conecting Lambda function to RDS on AWS

I'm trying to connect to a msql database on AWS using the following lambda function
const dotenv = require('dotenv');
dotenv.config();
var mysql = require('mysql');
var pool = mysql.createPool({
host : process.env.DBHOST,
user : process.env.DBUSER,
password : process.env.DBPASSWORD,
database : process.env.DBNAME
});
exports.handler = (event, context, callback) => {
//prevent timeout from waiting event loop
context.callbackWaitsForEmptyEventLoop = false;
pool.getConnection(function(err, connection) {
// Use the connection
connection.query('select * from products', function (error, results, fields) {
// And done with the connection.
connection.release();
// Handle error after the release.
if (error) callback(error);
else callback(null,results[0].emp_name);
});
});
};
When executed it gives the following error:
Response:
{
"errorMessage": "2020-12-05T16:51:55.273Z 281776f1-ee7f-4c8c-8862-a7371d1a8f37 Task timed out after 3.00 seconds"
}
Request ID:
"281776f1-ee7f-4c8c-8862-a7371d1a8f37"
Function logs:
START RequestId: 281776f1-ee7f-4c8c-8862-a7371d1a8f37 Version: $LATEST
END RequestId: 281776f1-ee7f-4c8c-8862-a7371d1a8f37
REPORT RequestId: 281776f1-ee7f-4c8c-8862-a7371d1a8f37 Duration: 3003.58 ms Billed Duration: 3000 ms Memory Size: 128 MB Max Memory Used: 75 MB Init Duration: 202.41 ms
2020-12-05T16:51:55.273Z 281776f1-ee7f-4c8c-8862-a7371d1a8f37 Task timed out after 3.00 seconds
How do I fix this?
This seems like a communication issue.
Make sure that the lambda can reach the RDS. Either they are deployed on same VPC, or there is a path from the lambda to the RDS.
Make sure that the RDS has a security group with an inbound rule to allow connection from the lambda (protocol, port, ip range or security group)
Also, verify that the lambda has the appropriate privileges (i.e. AWS IAM Role) to support your desired action.

aws linux server crashing after deployment

I have been running my reactJS website for about one year so far and there's server crashing happened(this start to happen in the last 3 months) when each time I did a deployment(after doing the deployment it works fine but) & on the next day morning when I tried to log in to my website I couldn't access it & I have to restart my PM2 server to make it work again. but from last week my whole AWS instance crashed & I can't find why that happened, from last week this happened to me 2 times. then I have to go to AWS web and restart the server(before I have started using the console but since now I couldn't access it via console have to go to the AWS web and start it again).
also when 1st-time server crashing happens I got that my MySQL server closed the connection since I got it from the logs:
db error Error: Connection lost: The server closed the connection. at Protocol.end (/home/ubuntu/CIAO_ERP/node_modules/mysql/lib/protocol/Protocol.js:112:13) at Socket.<anonymous> (/home/ubuntu/CIAO_ERP/node_modules/mysql/lib/Connection.js:94:28) at Socket.<anonymous> (/home/ubuntu/CIAO_ERP/node_modules/mysql/lib/Connection.js:526:10) at Socket.emit (events.js:215:7) at Socket.EventEmitter.emit (domain.js:475:20) at endReadableNT (_stream_readable.js:1184:12) at processTicksAndRejections (internal/process/task_queues.js:80:21) { fatal: true, code: 'PROTOCOL_CONNECTION_LOST' }
then I have used this solution :stackoverflow answer for handling 'PROTOCOL_CONNECTION_LOST'
then I handled that issue but still, a connection loss appears.
anyway, I'm attaching my connection handling and my server code segments to check whether if I did anything wrong!
SERVER.js
const express = require("express");
const cors = require("cors");
const { DBConnect } = require("./connection");
DBConnect();
const path = require("path");
const app = express();
app.use(express.json({ limit: "50mb", extended: true }));
app.use(
express.urlencoded({ limit: "50mb", extended: true, parameterLimit: 50000 })
);
app.use(cors());
app.use("/api/users", require("./routes/api/users"));
app.use("/api/invoiceSetting", require("./routes/api/InvoiceSetting"));
app.use("/api/auth", require("./routes/api/auth"));
app.use("/api/appSetting", require("./routes/api/AppSetting"));
app.use("/api/StakeHolder", require("./routes/api/StakeHolderSetting"));
app.use("/api/warehouse", require("./routes/api/WarehouseSetting"));
app.use("/api/production", require("./routes/api/ProductionSetting"));
app.use("/api/purchasing", require("./routes/api/Purchasing"));
app.use("/api/purchasingTemp", require("./routes/api/PurchasingTemp"));
//serve static assets if in production
app.use(express.static(path.join(__dirname, "../..", "build")));
const port = process.env.PORTADDRESS || 5000;
app.listen(port, () => console.log(`listening on http://localhost:${port}`)).on(
"error",
(err) => {
console.log(`catched error on listen & error is ${err}\n`);
}
);
here is my DB connection handling code
const mysql = require("mysql");
require("dotenv").config();
let portDB = process.env.PORT_DB;
console.log("PORT ENV VARIABLE:", portDB);
if (portDB === undefined) {
process.exit();
}
var db_config = {
host: process.env.HOST_NAME,
user: process.env.USER_NAME,
password: process.env.PASSWORD,
database: process.env.DATABASE,
multipleStatements: true,
port: portDB,
};
let db = mysql.createConnection(db_config);
const handleDisconnect = () => {
db = mysql.createConnection(db_config);
db.connect((err) => {
// The server is either down
if (err) {
// or restarting (takes a while sometimes).
console.log("error when connecting to db:", err);
console.log("& restarting");
setTimeout(handleDisconnect, 2000); // We introduce a delay before attempting to reconnect,
} // to avoid a hot loop, and to allow our node script to
else {
console.log("Connected Mysql DB!");
}
}); // process asynchronous requests in the meantime.
// If you're also serving http, display a 503 error.
db.on("error", (err) => {
console.log("db error", err);
if (err.code === "PROTOCOL_CONNECTION_LOST") {
console.log(`err.code : PROTOCOL_CONNECTION_LOST appeard\n`);
// Connection to the MySQL server is usually
handleDisconnect(); // lost due to either server restart, or a
} else {
// connnection idle timeout (the wait_timeout
console.log(`db.on("error") else called & err : ${err}\n`);
throw err; // server variable configures this)
}
});
};
module.exports = {
db: db,//this db is used to handling mysql queries
DBConnect: handleDisconnect,//this is used to start the db
};
I would be glad if any help me to solve this server crashing problem or whole AWS instance crashing problem I'm facing right now :(

Error connecting AWS RDS MYSQL from AWS Lambda Node.js

I am trying to connect AWS RDS Mysql from Lamda function written in Node.js. Initially I was getting "timed out" error, then I made below configuration.
-The Lambda execution role has full access to VPC.
-The Lambda function and the RDS instances are now in the same VPC.
-The Lambda function and the RDS instances are in same subnets.
-The Lambda function and the RDS instances shares a security group.
-All inbound traffic permitted.
Now I says that the DB I am trying to connect is unknown.Giving below error:
Response:
{
"errorType": "Error",
"errorMessage": "ER_BAD_DB_ERROR: Unknown database 'empdb'",
"trace": [
"Error: ER_BAD_DB_ERROR: Unknown database 'empdb'",
I am copying the code snippet as well.
var mysql = require('mysql');
var connection = mysql.createConnection({
host : process.env.RDS_HOSTNAME,
user : process.env.RDS_USERNAME,
password : process.env.RDS_PASSWORD,
port : process.env.RDS_PORT,
database : process.env.RDS_DATABASE
});
connection.connect();
exports.handler = (event, context, callback) => {
// allows for using callbacks as finish/error-handlers
context.callbackWaitsForEmptyEventLoop = false;
const sql = "insert into MESSAGE values('Testing1');";
connection.query(sql, (err, res) => {
if (err) {
throw err
}
callback(null, '1 records inserted.');
})
};
I tried both Create and Insert statements. I am new to AWS. Please advise.

RDS MySQL timing out intermittently when called from Lambda using NodeJS

My web app uses Lambda using NodeJS and backend is RDS(MySQL). I'm using serverless-mysql to make db calls.
For some reason, the db call times out intermittently. I tried the following:
Enabled flow logs to see if there are any errors (but couldn't find any reject statuses).
Tried making the database publicly available and took lambda out of VPC (to see if it is an issue with VPC configuration). But still, it was failing intermittently. So VPC is out of the equation.
RDS is not having any unusual spikes and connection exhaustion as monitoring shows a peak of only up to 3 connections. Lambda is always kept warm. I tried increasing the time out to up to 25 seconds. Still no luck.
Below is the code I use:
export async function get(event, context, callback) {
if (await warmer(event)) return 'warmed';
context.callbackWaitsForEmptyEventLoop = false;
try {
const userId = getUserIdFromIdentityId(event);
const query = "select * from UserProfile where UserId = ?";
const result = await mysql.query(query, [userId]);
console.log(result);
console.log('getting user account');
mysql.quit();
return success({
profileSettings: result.length > 0 ? result[0] : null,
});
} catch(e) {
console.log(e);
return failure();
}
}
Success function basically returns a json object like below:
return {
statusCode: 200,
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Credentials": true
},
body: JSON.stringify(body)
};
mysql is initialized as below:
export const mysql = AWSXray.captureMySQL(require('serverless-mysql')({
config: {
host: process.env.dbHost,
user: process.env.dbUsername,
password: process.env.dbPassword,
database: process.env.database,
}
}));
The only error I can see in Cloudwatch logs is:
Task timed out after 10.01 seconds.