Serverless with nodejs and mysql => Process exited before completing request - mysql

I'm developing some functions with serverless with the nodejs template. I have a service that connects to a mysql database and retrieves some data. Everything is fine when I make the first call, but when I repeat it I receive a "Process exited before completing request" error message.
If I try that same call again, I receive data. So the service is doing right on the odd calls and it's returning the error on the even calls (funny right?). This is the code of the handler function:
module.exports.getAll = (event, context, done) => {
deviceRepository.getAllDevices().then((response) => {
done(null, { response });
}).catch((error) => {
done(error);
});
};
and this is the code of the repository function:
const mysql = require('mysql');
const when = require('when');
const config = require('./config');
const conn = mysql.createConnection({
host: config.RDSHOST,
user: config.RDSUSER,
password: config.RDSPASS,
database: config.RDSDB,
port: config.RDSPORT
});
module.exports.getAllDevices = () => {
const deferred = when.defer();
conn.connect();
conn.query('SELECT * FROM device', (err, rows) => {
if (err) {
deferred.reject(err);
} else {
deferred.resolve(rows);
}
conn.end();
});
return deferred.promise;
};
As you can see I use promises with the 'when' library. I call the 'done' callback in the handler, and there should be a response from the promise in every possible situation.
I can't see what is wrong with this and why is making the odd requests wrong. Anyone can help?
Thanks in advance!

Solved by myself...
The problem is that I was making the createConnection outside of the handler (when I declared the conn constant).
Moving the createConnection declaration inside the handler function works as expected in every call.
const mysql = require('mysql');
const when = require('when');
const config = require('./config');
module.exports.getAllDevices = () => {
const conn = mysql.createConnection({
host: config.RDSHOST,
user: config.RDSUSER,
password: config.RDSPASS,
database: config.RDSDB,
port: config.RDSPORT
});
const deferred = when.defer();
conn.connect();
conn.query('SELECT * FROM device', (err, rows) => {
if (err) {
deferred.reject(err);
} else {
deferred.resolve(rows);
}
conn.end();
});
return deferred.promise;
};
Hope this helps. Thanks!

Related

Why I'm always getting an Internal Server Error (code 500) after making a request to BackEnd

I'm having a little trouble with my site and I can't understand what is happening.
First of all I have to say that I was NOT having this behavior when developing on localhost, but now that my site is close to be completed I think that uploading my code to a hosting service and make some tests there would be a good idea.
The issue is that when I make a request to the database, most of the times the site keeps in an eternal loading state, until the error code 500: Internal Server Error appears (I said "most of the times" because it works nice sometime, but normally it remains in a pending state).
Given the fact that SOME TIMES the request work nice, makes me think that the issue is not on the server.js file (where I defined the endpoints), and also is not on my controllers files (where I have some logic and the requests itself).
I'll leave here some pics as example of what is happening but if you need some extra info just tell me:
A simple login example, I just fill the fields and send the request
And here you can see how the request remain as pending
Until it fails
EDIT: I'm using package Mysql2 to connect to the DB, and I was reading that this behavior may be because a bad use of connections (and I'm reading about "pools", but I'm kinda lost tbh)
Here is the connection file:
require("dotenv").config();
const mysql = require("mysql2");
const db = mysql.createConnection({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
waitForConnections: true,
});
const connection = async () => {
db.connect((err) => {
if (err) throw err;
console.log("Successfully connected");
})
}
exports.db = db;
exports.connection = connection;
The first call to the DB (just to check the connection)
connection().then(() => {
app.listen(port, () => {
console.log(`Server running at ...`);
});
});
And the login logic
app.post("/dev-end/api/login", async (req, res) => {
await singleAccount(db, req.body.email)
.then(async (response) => {
if (response.code) {
res.render("templateLogin");
}
try {
if (await bcrypt.compare(req.body.password, response.password)) {
const user = { id: response._id, name: response.name };
await deleteTokenById(db, user.id.toString());
const accessToken = generateAccessToken(user);
const refreshToken = jwt.sign(
user,
process.env.REFRESH_TOKEN_SECRET,
{ expiresIn: "604800s" }
);
createToken(db, {
_id: user.id,
accessToken: accessToken,
refreshToken: refreshToken,
createdAt: new Date().toISOString().slice(0, 19).replace("T", " "),
}).then(
res
.cookie("access_token", accessToken, {
httpOnly: true,
maxAge: 60000 * 60 * 24 * 7,
})
.redirect("/dev-end/dashboard")
);
} else {
res.render("templateLogin");
}
} catch {
res.status(500).send();
}
})
.catch(console.log);
});
=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>
const singleAccount = async (conn, email) => {
return await read(conn).then((res) => {
if (!res.code) {
const result = res.find((e) => e.email.toString() === email);
if (!result) {
return {
code: 404,
msg: "No account was found with the provided id",
};
}
return result;
}
return res;
});
};
=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>
const read = async (conn) => {
const sql = `SELECT * FROM accounts`;
return await conn.promise().query(sql)
.then(([res, fields]) => res);
};

In node.js, How to return mysql results from a function?

I tried to separate function to another file, as the function fetching data from mysql database.
This is db.js
const mysql = require('mysql');
var con = mysql.createConnection({
host: "localhost",
user: "root",
password: "",
database: "sample"
});
con.connect()
module.exports = function(query) {
con.query(query, function (err, result) {
if (err){
console.log(err);
} else{
console.log(result)
return result
}
});
};
This is main.js
const express = require('express')
const db = require('./db')
const app = express()
app.get('/test', function(req, res){
var sql = "SELECT id FROM user"
console.log(db(sql))
res.send(db(sql))
});
In main.js on console.log(db(sql)) got undefined.
But in db.js on console.log(result) I got the values as:
[
RowDataPacket { id: 1 },
RowDataPacket { id: 2 },
RowDataPacket { id: 3 }
]
Why did I get undefined in the main.js? Is there any solution for this issue?
Since you are using callback function, you can't directly return the value from it.
you have 2 options to do what you want to do.
Promise
Async/Await (mysql2 module needed)
Try this,
Querying
function(query) {
return new Promise((resolve, reject) =>{
try{
con.query(query, function (err, result) {
if (err){
return reject(err)
}
return resolve(result)
});
}
catch(e){
reject(e)
}
})
};
Main
app.get('/test', async function(req, res){
var sql = "SELECT id FROM user"
try{
const userId = await db(sql)
return res.send({
success: true,
result: {
userId
}
})
}
catch(e){
console.error(e)
return res.status(500).send({
success: false,
message: 'internal server error'
})
}
})
One more thing, if you have a good reason to write query by yourself, you can use
knex for making it easier (https://www.npmjs.com/package/knex), which is a query builder, meaning doing nothing to do with database connection.
Sollution
Try async/await with mysql2
Dont go for mysql2/primse because it will cause unexpected errors when your database is in the cloud or deployed somewhere like clearDB addons provided by Heroku
Follow these steps...
create config file for your database connection seperately
import mysql from 'mysql2'
let db = mysql.createPool({
host: 'your host name',
user: "your username",
password: "your password",
database: "your database name",
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
})
export { db }
execute the query the same like this i am doing
import {db} from 'where you defined the above db config'
app.get('/test', async function(req, res){
const promise= db.promise()
var sql = "SELECT id FROM user"
const [rows,field] = awiat promise.execute(sql)
res.send(rows)
});

AWS Lambda nodejs mysql query inside loop is not working

module.exports.handler = async (event, context, callback) => {
context.callbackWaitsForEmptyEventLoop = false;
let index = 0;
var client = mysql.createConnection({
host: process.env.rds_host,
user: process.env.rds_username,
password: process.env.rds_password,
port: process.env.rds_port
});
client.connect((err) => {
if (err) throw err;
console.log("Connected!");
});
let array = [];
let queries = ["query1", "query2", "query3", "query4"];
queries.map(q => {
array.push(getQueryResult(client, q));
});
Promise.all(array).then(result => {
console.log(result);
});
callback(null, {});
};
const getQueryResult = async (client, query) => {
return new Promise((resolve, reject) => {
client.query(query, function (err, result) {
if (err) {
reject(err);
}
resolve(result);
});
});
};
Above is my lambda scripts to execute multiple query from mysql. The problem is I didn't get any result and error message from above scripts. Please help me something is missing inside my scripts?
The issue is >> code is not waiting to finish Promise
You can resolve by :
Add callback in then
Promise.all(array).then(result => {
console.log(result);
callback(null, {});
});
OR
Use await
let result = await Promise.all(promiseArray);
console.log(result)
callback(null, {});
Note: Use try-catch to handle error in for await
Also, don't use map to loop array instead use For loop.
There are two or three (potential) issues with your code above:
Your if statement does not get evaluated because of the typeof client predicate does not return true.
your mysql port conflicts with your localhost port (assumption)
Change your if block as such:
// check if `dotenv` has been called if you use it
require('dotenv').config();
// access the state property on mysql object
// if you have closed your connection previously
// this will get evaluated by the parser
if (mysql.state === "disconnected") {
var client = mysql.createConnection({
host: process.env.rds_host,
user: process.env.rds_username,
password: process.env.rds_password,
port: process.env.rds_port // is your port the same as your localhost?
// include your database name here
});
// I suggest you to await your client connection
// since mysql executes sequentially, not asynchronously
client.connect(function(err) => {
if (err) {
console.error('error connecting: ' + err.stack);
return;
}
console.log("Connected!");
});
}
if the error persists, it means that your enviroment variables are not set correctly so your db configuration should be reviewed (see inline comments).

NodejS express ReferenceError: connection is not defined

I am creating a simple server application using the following code
const express = require('express');
const mysql = require('mysql');
const PORT = process.env.PORT || 3000;
const app = express();
const connection = mysql.createConnection({
host: 'localhost',
user: 'user',
password: 'password',
database: 'mydata',
});
connection.connect(function (err) {
err ? console.log(err) : console.log(connection);
});
require('./routes/html-routes')(app);
app.listen(PORT, () => {
console.log('app running on port %s', PORT);
});
module.exports = app;
in file server.js
and then a route in file html-routes.js
const mysql = require('mysql');
module.exports = function (app) {
app.get('/', function (req, res) {
connection.query('select * from mydata;', function (err, data) {
err ? res.send(err) : res.json({ mydata: data });
});
});
};
to get data from database
I get the error
ReferenceError: connection is not defined
at /Users/arjunbhandari/Desktop/GL-IT/backend/routes/html-routes.js:5:5
I have struggled for the past 6 hours and cannot understand the problem.
Thanks
As the error states, there is no connection defined (or inherited) within ./routes/html-routes.js.
You still can pass the connection property as a second argument to your exported function:
const mysql = require('mysql');
module.exports = function (app, connection) {
app.get('/', function (req, res) {
connection.query('select * from mydata;', function (err, data) {
err ? res.send(err) : res.json({ mydata: data });
});
});
};
then update the route mounting call within your main server file:
require('./routes/html-routes')(app, connection);
You should review your route implementation logic as this should not be the best design approach to use data-store connections.

node.js mysql pool connection with async/ await

Is there a way to use pool.getConnection() taken from the mysqljs/mysql lib with the async/ await syntax?
The idea is to have a method which returns one connection which can be passed around amongst write queries with various foreign key constraints (sequential queries) before releasing it and at the same time potentially get further connections from the pool for the purpose of various read queries (parallel).
Share my working example:
I use this Promisified MySQL middleware for Node.js
read this article Create a MySQL Database Middleware with Node.js 8 and Async/Await
here is my database.js
var mysql = require('mysql');
// node -v must > 8.x
var util = require('util');
// !!!!! for node version < 8.x only !!!!!
// npm install util.promisify
//require('util.promisify').shim();
// -v < 8.x has problem with async await so upgrade -v to v9.6.1 for this to work.
// connection pool https://github.com/mysqljs/mysql [1]
var pool = mysql.createPool({
connectionLimit : process.env.mysql_connection_pool_Limit, // default:10
host : process.env.mysql_host,
user : process.env.mysql_user,
password : process.env.mysql_password,
database : process.env.mysql_database
})
// Ping database to check for common exception errors.
pool.getConnection((err, connection) => {
if (err) {
if (err.code === 'PROTOCOL_CONNECTION_LOST') {
console.error('Database connection was closed.')
}
if (err.code === 'ER_CON_COUNT_ERROR') {
console.error('Database has too many connections.')
}
if (err.code === 'ECONNREFUSED') {
console.error('Database connection was refused.')
}
}
if (connection) connection.release()
return
})
// Promisify for Node.js async/await.
pool.query = util.promisify(pool.query)
module.exports = pool
You must upgrade node -v > 8.x
you must use async function to be able to use await.
example:
var pool = require('./database')
// node -v must > 8.x, --> async / await
router.get('/:template', async function(req, res, next)
{
...
try {
var _sql_rest_url = 'SELECT * FROM arcgis_viewer.rest_url WHERE id='+ _url_id;
var rows = await pool.query(_sql_rest_url)
_url = rows[0].rest_url // first record, property name is 'rest_url'
if (_center_lat == null) {_center_lat = rows[0].center_lat }
if (_center_long == null) {_center_long= rows[0].center_long }
if (_center_zoom == null) {_center_zoom= rows[0].center_zoom }
_place = rows[0].place
} catch(err) {
throw new Error(err)
}
Mates. I don't know why but I tried all the day long but couldn't get it to work. By the help of your comments I tried again and it of course does work.
db.js:
const pool = mysql.createPool(config);
exports.getConnection = () => {
return new Promise((resolve, reject) => {
pool.getConnection(function (err, connection) {
if (err) {
return reject(err);
}
resolve(connection);
});
});
};
someWhereElse.js:
const db = require('./db');
const wrappingFunction = async () => {
const connection = await db.getConnection();
console.log(connection);
};
wrappingFunction();
Seems like implementing promises manually is a better option.
Just sharing what I have used in my code -
const mysql = require('mysql');
const config = require('config');
const pool = mysql.createPool(config.get('db.mysql'));
module.exports = {
checkConnection: () => {
return new Promise((resolve, reject) => {
pool.getConnection((err, conn) => {
if (err) {
return reject(err);
}
resolve(conn.release());
});
});
},
pool,
closeConnection: () => pool.end(),
};
Previous answers (with util.promisify) did not work for me, and only implementing Promise manually works:
Function:
async function removeItem (id) {
return new Promise( (resolve) => {
pool.query('DELETE FROM table_name WHERE id=' + id, (error) => {
resolve ({result: !error});
});
});
}
Usage:
const app = express();
const mysql = require('mysql');
const pool = mysql.createPool({
connectionLimit: 10,
host: 'localhost',
user: 'login',
password: 'pass',
database: 'dbname'
});
app.post("/:id", async (req, res) => {
const answer = await itemRemove(id);
res.send(answer);
});
Sure, you would have to promisify it first, which you can do since node 8.0.0 now:
const util = require('util');
async function doSomething() {
const getConnectionAsync = util.promisify(pool.getConnection);
try {
const result = await getConnectionAsync('MASTER');
}catch(err) {
console.log('Oh no');
}
}
If for some reason you can't use node 8 or above, there are other ways to promisify it, like http://bluebirdjs.com/docs/api/promise.promisify.html
Just sharing what I've always use in my code:
//Filename: MySQL.js
module.exports = {
connect: function ()
{
return new Promise((resolve, reject) => {
let pool = Mysql.createPool({ //require configfile.js or just put connection detail here
connectionLimit: config.mysql.connectionLimit,
host: config.mysql.host,
user: config.mysql.user,
password: config.mysql.password,
database: config.mysql.database
});
pool.getConnection((err, connection) =>
{
try
{
if (connection)
{
resolve({"status":"success", "data":"MySQL connected.", "con":pool});
connection.release();
}
}
catch (err)
{
reject({"status":"failed", "error":`MySQL error. ${err}`});
}
resolve({"status":"failed", "error":"Error connecting to MySQL."});
});
});
}
}
Then whenever you need to call the connection to MySQL
//Filename: somefile.js
const useMySQL = require('./path/to/MySQL');
module.exports = {
getSomething: function () {
return new Promise(async (resolve) => {
try
{
let connection = await useMySQL.connect();
con = connection.con;
//Do some query here, then
resolve(`Send some result/handle error`);
}
catch (err)
{
//Handle error if any, log, etc, and eventually
resolve(err);
}
});
}
Hope this helps.