Serverless Framework with Node MySQL - mysql

How to use mysql connection with serverless framework.connection should be available in my component functions without creating mysql connection each time in component function
Tried like this
var mysql = require('mysql');
module.exports.respond = function(event, cb) {
var pool = mysql.createPool({
connectionLimit : 100,
host : 'hostname',
user : 'username',
password : 'password',
database : 'databasename',
debug : false
});
var message='';
pool.getConnection(function(err,connection){
if(err) {
message='Could not connect to database';
} else {
message="Database is connected";
}
var response = {
message: message
};
return cb(null, response);
});
};
but above code will be only available for current function,want to make common thing for mysql connection in serverless framework,can not find proper document about how to use mysql in serverless framework

I am writing answer of my own question
make database.js file in component/lib folder
code of database.js
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'hostname',
user : 'username',
password : 'password',
database : 'databasename'
});
connection.connect();
module.exports = connection;
created object like this in component/lib/index.js file
var connection = require("../lib/database.js");
Can use connection variable to write mysql query like this in component/lib/index.js
module.exports.respond = function(event, cb) {
var query="SELECT * from table_name";
connection.query(query,function(err,rows) {
})
};

I believe you have a Component created in your Serverless Framework based project that contains multiple lambda functions. And now you want to write the MySQL connection code such that this code block is available for re-use in all your lambda functions of that component.
If this is the ask, then Serverless does provide a "lib" folder inside your Component directory, which you can utilize to write common code logic to be re-used. Since you have a NodeJS-based runtime for your component, there should be an "index.js" file inside your Component folder -
your_serverless_project_directory/component_name/lib/index.js
The first thing you want to do is to add the MySQL connection code logic to a function/method in index.js.
Serverless should have already included for you this entire lib/ folder in all your lambda function's handler.js code like this -
var lib = require('../../lib');
Therefore, the next/final thing you want to do is re-use your connection function/method (in all the lambda functions belonging inside your Component) like this -
module.exports.handler = function(event, context) {
lib.mySQLConnection();
};
Hope this helps, let me know how it goes.

To build off of Normal Goswami's answer:
You've specified the database here in the connection. My lambdas each need different databases, so in the connection code just leave off the database:
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'hostname',
user : 'username',
password : 'password'
// no database here
});
connection.connect();
module.exports = connection;
And then use an oddly named function to change the database in each lambda function:
connection.changeUser({database: database}, function(err) {
if (err) { throw err; }
});
connection.query(sql, function(err, rows, fields) {
// etc
}
You could also look into using a database connection pool.

you have to make connection out of function, as we are doing it with mongodb
we are making mongodb connection out side of Lambda Function.
my code snippet from https://github.com/malikasinger1/serverles-practice/tree/master/mongodb-connection:
var mongoose = require("mongoose");
var dbURI = 'mongodb://localhost/mydatabase';
mongoose.connect(dbURI);
mongoose.connection.on('connected', function () {//connected
console.log("Mongoose is connected");
// process.exit(1);
});
module.exports.signup = (event, context, cb) => {
//doing signup here
}
in your cace it will be something like this most probably:
var mysql = require('mysql');
//make connection here
var pool = mysql.createPool({
...
});
pool.getConnection(function(err,connection){
...
});
module.exports.respond = function(event, cb) {
//use connection here
};

I am assuming you are using serverless framework on AWS.
Although you can create a connection and assign it to a frozen variable, it's not guaranteed that your lambda won't create a new connection. Here is why:
The best way so far (in my personal opinion) is to create a separate lambda function for db related operations and invoke this function through other lambdas. Here is the flow:
client -> registerUserLambda -> dbLambda -> DATABASE
However, the thing about lambdas is that when there are too many requests, there will be new containers created to handle other requests. That is, new connections will be created. Therefore the concept of connection pools does not work well for now on serverless lambdas.

Related

How to make Alexa run MySQL Querys through a skill

I am trying to set up an alexa skill that calls MySQL Querys when a certain question gets asked. Nothing I tried seemed to work because I either get an error or nothing happens at all.
I am using/what I am working with:
Alexa Developer Console
Cloud9 as IDE(which uploads the code to AWS Lambda, where I defined the environmental variables used in my code)
AWS Lambda, NodeJS
Amazon RDS, which hosts my DB instance
MySQL Workbench (where I created a few tables to test the database, which works fine)
I tried several ways to solve my problem, like creating a connection or a pool, but I think it has to be handled differently, because Alexa has to wait for the response.
const GetOeffnungszeiten_Handler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest' && request.intent.name === 'GetOeffnungszeiten' ;
},
handle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
const responseBuilder = handlerInput.responseBuilder;
let sessionAttributes = handlerInput.attributesManager.getSessionAttributes();
let say = 'OUTPUT: ';
var mysql = require('mysql');
var connection = mysql.createPool({
host : process.env.MYSQL_HOSTNAME,
user : process.env.MYSQL_USERNAME,
password : process.env.MYSQL_PASSWORD,
database : process.env.MYSQL_DATABASE,
port : process.env.MYSQL_PORT
});
exports.handler = (event, context, callback) => {
context.callbackWaitsForEmptyEventLoop = false;
pool.getConnection(function(err, connection) {
connection.query('select name from persons where id=1', function (error, results, fields) {
connection.release();
if (error) {
callback(error);
say=say+'0';
} else {
callback(null,results[0].name);
say=say+' 1';
}
});
});
};
return responseBuilder
.speak(say)
.reprompt('try again, ' + say)
.getResponse();
},
};
I expect the output to either be "OUTPUT: 1" or "OUTPUT: 0" but it is "OUTPUT: "
With output I refer to the say variable.
Your function is returning responseBuilder...getResponse() before the SQL connection finishes and callback is called.
I would suggest to refactor your code using async and await to make it easier to read and to understand. (read https://stormacq.com/2019/06/22/async-js.html for help)
Be sure to return the Alexa response only when your call to MySQL returns, and not before. Remember that Alexa timeout is 8 secs, so your code need to return before that. Be sure that the AWS Lambda timeout is aligned to the Alexa timeout too (put it at 7 secs)
Finally, I would advise against using MySQL for Alexa skills. Because each Lambda invocation might be served by different containers, your code will create a connection pool for each interaction between customers and your skill, creating a significant delay to bring a response to customers. DynamoDB and Elastic Cache are much better suited to Alexa skills.

Create Lambda Function CRUD to RDS MySQL in Node.js

I am investigating how to create functions, in Lambda, against MySQL. I have seen tutorials on the internet, but I can not do it. I've only been able to do the GET method.
How do I manage the variables, to make a DELETE or a PUT?
Currently, I did this function.
const mysql = require('mysql');
const con = 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
});
exports.handler = (event, context, callback) => {
// allows for using callbacks as finish/error-handlers
context.callbackWaitsForEmptyEventLoop = false;
const sql = "SELECT * FROM usuarios";
con.query(sql, function (err, result) {
if (err) throw err;
callback(null, result)
});
};
Here it's the database
My Lambda Function
And my API Gateway
I hope to create a function to delete a record. It is not a productive environment, just to learn! I appreciate, if you help me! Regards!

How to debug an Azure Function using Node.js and mysql2 connecting to database

running into some issues trying to figure out an Azure Function (node.js-based) can connect to our mysql database (also hosted on Azure). We're using mysql2 and following tutorials pretty much exactly (https://learn.microsoft.com/en-us/azure/mysql/connect-nodejs, and similar) Here's the meat of the call:
const mysql = require('mysql2');
const fs = require('fs');
module.exports = async function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
if (req.query.fname || (req.body && req.body.fname)) {
context.log('start');
var config = {
host:process.env['mysql_host'],
user: process.env['mysql_user'],
password: process.env['mysql_password'],
port:3306,
database:'database_name',
ssl:{
ca : fs.readFileSync(__dirname + '\\certs\\cacert.pem')
},
connectTimeout:5000
};
const conn = mysql.createConnection(config);
/*context.log(conn);*/
conn.connect(function (err) {
context.log('here');
if (err) {
context.error('error connecting: ' + err.stack);
context.log("shit is broke");
throw err;
}
console.log("Connection established.");
});
context.log('mid');
conn.query('SELECT 1+1',function(error,results,fields) {
context.log('here');
context.log(error);
context.log(results);
context.log(fields);
});
Basically, running into an issue where the conn.connect(function(err)... doesn't return anything - no error message, no logs, etc. conn.query works similarly.
Everything seems set up properly, but I don't even know where to look next to resolve the issue. Has anyone come across this before or have advice on how to handle?
Thanks!!
Ben
I believe the link that Baskar shared covers debugging your function locally
As for your function, you can make some changes to improve performance.
Create the connection to the DB outside the function code otherwise it will create a new instance and connect every time. Also, you can enable pooling to reuse connections and not cross the 300 limit that the sandbox in which Azure Functions run has.
Use the Promises along with async/await
You basically can update your code to something like this
const mysql = require('mysql2/promise');
const fs = require('fs');
var config = {
host: process.env['mysql_host'],
user: process.env['mysql_user'],
password: process.env['mysql_password'],
port: 3306,
database: 'database_name',
ssl: {
ca: fs.readFileSync(__dirname + '\\certs\\cacert.pem')
},
connectTimeout: 5000,
connectionLimit: 250,
queueLimit: 0
};
const pool = mysql.createPool(config);
module.exports = async function(context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
if (req.query.fname || (req.body && req.body.fname)) {
context.log('start');
const conn = await pool.getConnection();
context.log('mid');
await conn.query('SELECT 1+1', function(error, results, fields) {
context.log('here');
context.log(error);
context.log(results);
context.log(fields);
});
conn.release();
}
};
PS: I haven't test this code as such but I believe something like this should work
Debugging on serverless is challenging for obvious reasons. You can try one of the hacky solutions to debug locally (like Serverless Framework), but that won't necessarily help you if your issue is to do with a connection to a DB. You might see different behaviour locally.
Another option is to see if you can step debug using Rookout, which should let you catch the full stack at different points in the code execution and give you a good sense of what's failing and why.

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.

How to use express.js with mysql and express-myconnection?

I am using Express 4.9.0 and express-generator. Executed this command:
express --hbs projectname
Installed following modules with NPM:
mysql
express-myconnection
I want to make todo application. I have created separate file under routes/todo.js and created get/post routes for creating todos in that file using router.get and router.post.
i have following code in app.js:
// mysql connection
var connection = require('express-myconnection');
var mysql = require('mysql');
app.use(
connection(mysql, {
host : config.db.host,
user : config.db.user,
password : config.db.password,
database : config.db.database,
debug : false //set true if you wanna see debug logger
}, 'request')
);
// end of mysql connection
Where should i place mysql config and connection code? Inside todo.js? I still don't get concept of organisation file structure and where to place database queries.
I don't know if you eventually found the answer, but I thought it might help out others who accidentally stumbled on your question:
After you've setup like mentioned above, you can call the connection from the request object using the getConnection method like this:
exports.index = function(req, res) {
req.getConnection(function (err, connection) {
connection.query('select * from table_name', function(err, rows, fields){
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.jsonp(rows);
}
});
});
};
This should print out a json with the content of your table all nice an pretty.
Hope this comes in handy.