NodeJS (Express) with MySQL - How to handle connection resets? - mysql

I'm running my website with NodeJS, I'm using the Express framework.
Since MySQL is the only database type at my hosting, I went with it.
I created a db.js file:
const mysql = require('mysql');
const con = mysql.createConnection({
host: .........
user: ...........
password: ............
database: ............
});
con.connect(function(err) {
if (err) {
//throw err;
console.error(err.message);
} else {
console.log('Connected Ro MySQL!');
}
});
module.exports = con;
And I using it like:
const db = require(path.join(__dirname, 'db'));
db.query('select * from table where name = ?', request.params.id, (error, result) => {
if (error) {
response.send(error.message);
} else {
//My Render Stuffs Here
});
}
});
My website works fine however sometimes let's say once every 2 weeks there is a MySQL connection reset, I think the database not available for a minute or so for some reason, and then my website crashes, I have to manually restart NodeJS what is very annoying.
Error in the console:
node:events:355
throw er; // Unhandled 'error' event
^
Error: read ECONNRESET
at TCP.onStreamRead (node:internal/stream_base_commons:211:20)
[...]
errno: -4077,
code: 'ECONNRESET',
syscall: 'read',
fatal: true
}
How should I change my codes to prevent crashing? I replaced throw err; with the console.error(err.message); but it only works when I start the website, not when a connection reset happens at runtime.

Found the solution: Replace createConnection with createPool and totally remove con.connect since createPool doesn't need it. That's it, now it's not crashes when the db unavailable.

Related

nodejs mysql on pool connection Error: Connection lost: The server closed the connection

My question is similar to this post but the solution didnt work for me probably because im using a different type of mysql connection (pool). This is my code:
let config= {
host: '***',
user: 'admin',
password: '***',
port: '3306',
database: '***',
multipleStatements: true
};
const con = mysql.createPool(config);
select();
function select(){
return new Promise((resolve, reject) => {
con.getConnection(function (err, connection) {
if (err) throw err;
else
console.log("Connected!");
let sql = "SELECT * FROM bidPrice WHERE idExchangePlatform = 2;";
connection.query(sql, function (err, results, fields) {
connection.release();
connection.destroy();
if (err) throw err;
console.log(results)
resolve(results);
});
});
});
}
I also important to mention that im running this function using the following command
node --max-old-space-size=31744 index.js # Increase to 31 GB
This is because im working with millions of records from the database query If i run this with regular node command i would be getting Javascript heap out of memory
When i tried integrating the solution i mentioned earlier to my code i just get a "killed" log after a while and then the process stops, should i handle server disconnect in a different way when using mysql.pool?

How to fetch data from MySQL database with Node

I'm new to react, developing a recipe-app and I got a problem while displaying the data from MySQL database. The connection was created successfully, however, I'm not sure about how to reach the data. When I run node server.js in my terminal, I get "connected", When I visit the localhost:8080/users, I get "This site can't be reached" message and in my terminal:
`events.js:187
throw er; // Unhandled 'error' event
^
Error: Cannot enqueue Handshake after already enqueuing a Handshake.`
I'm a little stuck here. Anyone knows a solution or direct me a little bit? Thank you so much!
Server.js
const express = require('express');
const app = express();
const PORT = 8080;
const mysql = require('mysql');
const connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'root',
database: 'recipe_app'
});
connection.connect((err) => {
if (err) throw err;
console.log('Connected!');
});
//creating route for the app
app.get('/users', (req, res) => {
connection.connect();
connection.query('SELECT * from users', function(err, rows, fields) {
if (!err) {
res.send(JSON.stringify(rows));
} else {
console.log('Error while performing Query.');
}
});
connection.end();
});
//making server listen to request
app.listen(PORT, () => {
console.log(`Server running at : http://localhost:${PORT}/`);
});
You're trying to reconnect to mysql after the connection has been established.
See my comments on the code below
const connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'root',
database: 'recipe_app'
});
connection.connect((err) => { // This creates the connection
if (err) throw err;
console.log('Connected!');
});
And when you're trying to resolve your GET routes, you're trying to connect again
//creating route for the app
app.get('/users', (req, res) => {
connection.connect(); // reconnect here
Since you're using the default connection method, trying to connect to an already established connection will cause the driver to throw a Handshake error.
If you want to re-use the connection, store it in a variable and then re-use it in other part of your code.
If you want to manage multiple connections instead, I suggest you to look at createPool instead.
Try removing the connection.connect() and connection.end() from app.get

Node.js server crashes after MySQL connection ends

I have a Node.js server that is hosting my webpage. I have recently set up a MySQL server and created a connection to the server. When accessing a certain page, it queries the SQL database.
My problem is that if I query the DB, it makes the connection just fine, but it will crash a little later when the server automatically closes the connection. I then tried to use con.end() after the query, but this crashes the second I access the DB. It throws the error below:
at Protocol._validateEnqueue (/home/pi/Documents/node_modules/mysql/lib/protocol/Protocol.js:203:16)
at Protocol._enqueue (/home/pi/Documents/node_modules/mysql/lib/protocol/Protocol.js:138:13)
at Connection.query (/home/pi/Documents/node_modules/mysql/lib/Connection.js:200:25)
at Handshake.con.connect (/home/pi/Documents/PageDB.js:26:9)
at Handshake.<anonymous> (/home/pi/Documents/node_modules/mysql/lib/Connection.js:502:10)
at Handshake._callback (/home/pi/Documents/node_modules/mysql/lib/Connection.js:468:16)
at Handshake.Sequence.end (/home/pi/Documents/node_modules/mysql/lib/protocol/sequences/Sequence.js:83:24)
at Handshake.Sequence.OkPacket (/home/pi/Documents/node_modules/mysql/lib/protocol/sequences/Sequence.js:92:8)
at Protocol._parsePacket (/home/pi/Documents/node_modules/mysql/lib/protocol/Protocol.js:278:23)
at Parser.write (/home/pi/Documents/node_modules/mysql/lib/protocol/Parser.js:76:12) code: 'PROTOCOL_ENQUEUE_AFTER_QUIT', fatal: false }
Close the database connection.
It seems to me that this is caused by the query executing after the con.end() runs. Can someone help me figure out a way to call the end function after the callback has returned with the SQL query data? Or otherwise, have my web server not crash when the connection to the DB is closed automatically? I'm open to either one. Thanks!
Code for the Node.js server is below:
//Create a connection to the db
const con = mysql.createConnection({
host: 'localhost',
user: 'test',
password: 'test',
database: 'test',
});
router.get('/products',(req,res)=>{
con.connect((err) => {
if(err){
console.log('Error relating to connection: ' + err);
return;
}
console.log('Connection established');
con.query('SELECT * FROM ProductList',(err,rows,fields)=>{
if(!err)
res.send(rows);
else
console.log(err);
})
});
con.end(function(err) {
if (err) {
return console.log('error:' + err.message);
}
console.log('Close the database connection.');
});
});
Your problem is that you're con.end is being called right after you connect method. As JS is asynchronous, so it will not wait for connect to end and then continue to end instead it will call connect and put the callback on the event queue and continue to next statement where you are closing your connection. So, what you should do is move your end statement inside the callback. Try using the following code
//Create a connection to the db
const con = mysql.createConnection({
host: 'localhost',
user: 'test',
password: 'test',
database: 'test',
});
router.get('/products', (req, res) => {
con.connect((err) => {
if (err) {
console.log('Error relating to connection: ' + err);
return;
}
console.log('Connection established');
con.query('SELECT * FROM ProductList', (err, rows, fields) => {
if (!err) {
res.send(rows);
con.end(function(err) {
if (err) {
return console.log('error:' + err.message);
}
console.log('Close the database connection.');
});
} else
console.log(err);
})
});
});

Server NodeJs crashes in idle time and how do I fix it?

My server api is on alwayse alwaysdata.
After x time the server crash.
events.js:183
throw er;
// Unhandled 'error' eventError: Connection lost: The server closed the connection.
at Protocol.end (/home/ec2-user/node_modules/mysql/lib/protocol/Protocol.js:112:13)
at Socket.<anonymous> (/home/ec2-user/node_modules/mysql/lib/Connection.js:97:28)
at Socket.<anonymous> (/home/ec2-user/node_modules/mysql/lib/Connection.js:502:10)
at emitNone (events.js:111:20)
at Socket.emit (events.js:208:7)
at endReadableNT (_stream_readable.js:1064:12)
at _combinedTickCallback (internal/process/next_tick.js:139:11)
at process._tickCallback (internal/process/next_tick.js:181:9)
I'm looking at whether this could not be related to a mysql error. but pre-existing posts do not help me. I think the server mysql cut the connection I do not know why.
here I establish the connection:
let con = mysql.createConnection({
host: "alwaysdata.net",
user: "user",
password: "",
database: "database"
});
try {
con.query(check, (err, customer) => {
if (err){
console.log("%s Error on check query",Date());
throw err;
}
try connection pool:
const mysql = require('mysql');
let pool = mysql.createPool(
{
connectionLimit : 100,
host : '172.17.0.1',
port : 3306,
user : 'test',
password : 'test',
database : 'test',
multipleStatements: true
}
);
...
pool.query(sql, params, function(err, rows) {
...
it works stably on my versions of mysql 5.7 and 8
I believe there are two ways you can handle this.
1) Force MySQL to keep the connection alive (not official, but I believe will do the trick).
2) Handle the mysql server disconnect from the Node's point of
view.
For both there is an excellent example here.
Server disconnects
You may lose the connection to a MySQL server due to network problems,
the server timing you out, the server being restarted, or crashing.
All of these events are considered fatal errors, and will have the
err.code = 'PROTOCOL_CONNECTION_LOST'. See the Error Handling section
for more information.
Re-connecting a connection is done by establishing a new connection.
Once terminated, an existing connection object cannot be re-connected
by design.
With Pool, disconnected connections will be removed from the pool
freeing up space for a new connection to be created on the next
getConnection call.
let connection=null;
function handleDisconnect() {
connection = mysql.createConnection({
host: "alwaysdata.net",
user: "user",
password: "",
database: "database"
}); // Recreate the connection, since
// the old one cannot be reused.
connection.connect(function (err) { // The server is either down
if (err) { // or restarting (takes a while sometimes).
console.log('error when connecting to db:', err);
setTimeout(handleDisconnect, 2000); // We introduce a delay before attempting to reconnect,
} // to avoid a hot loop, and to allow our node script to
}); // process asynchronous requests in the meantime.
// If you're also serving http, display a 503 error.
connection.on('error', function (err) {
console.log('db error', err);
if (err.code === 'PROTOCOL_CONNECTION_LOST') { // Connection to the MySQL server is usually
handleDisconnect(); // lost due to either server restart, or a
} else { // connnection idle timeout (the wait_timeout
throw err; // server variable configures this)
}
});
}
handleDisconnect();
setInterval(function () {
connection.query('SELECT 1');
}, 5000);
module.exports = connection;
you export the connection object and use this for the other connection queries.
I have called a Query every 5sec to keep the connection alive, i have tried all other approaches and this works like a charm.
Manish's answer worked for me!
I've been struggling with this for the past two days. I had a nodejs server with mysql db running on my localhost and after migrating to heroku with cleardb addon I came across several issues. I had this code in a config file:
const mysql = require('mysql');
const db = mysql.createConnection({
host: 'host',
database: 'database',
user: 'user',
password: 'password', });
module.exports = db;
I changed it to what Manish mentioned to handle the disconnect.

Why can't I send a response in Express from a mysql query?

I'll keep the code simple, but basically, I have a Node.js server running Express. Express is connected to a MySQL database using pooling (and the mysql npm package). This is what my server looks like (I left out the boring requires and whatnot to keep this simple). This is the only routing that the server handles.
server.all('/test', function (req, res, next) {
pool.getConnection(function (err, conn) {
if (err) {
console.log(err);
}
else {
conn.query("select * from spwp_appusers where id=46", function (err, rows) {
conn.release();
if (err) {
console.log(err);
}
else {
res.send(200);
}
});
}
});
next();
});
However, when I run this code, the server tries to execute res.send(200); but breaks and I get the following error:
/usr/lib/node_modules/mysql/lib/protocol/Parser.js:77
throw err; // Rethrow non-MySQL errors
^
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:335:11)
Does anyone know what is happening? Why can't I send the response? Even when I use a callback, I get this error.
I think the problem is with next. try changing next(); inside getConnection()
above error show in my case mismatch my mysql user,password,db name so please check your mysql credential.
var pool = mysql.createPool({
host: 'localhost',
user: 'root',
password: '',
database: 'dbname', multipleStatements: true
});