Node.js Mysql stopped querying after a few minutes - mysql

I have a Discord.js bot with a MySQL as a database. The problem I'm having is that the SQL stopped querying after a random amount of times, the only way that I could fix this is by restarting the node.js app
My bot involves a lot of sql querying inside of an sql query similar to :
sql.query(`SELECT xxxxx` , (err, res) => {
sql.query(`SELECT xxxxx`, (err, result) => {}
}
And my SQL pool code is :
const mysql = require('mysql');
const pool = mysql.createPool({
host : "localhost",
port : 3306,
user : "x",
password: "x",
database: 'x'
});
let sql = {};
sql.query = function(query, params, callback) {
pool.getConnection(function(err, connection) {
if(err) {
if (callback) callback(err, null, null);
return;
}
connection.query(query, params, function(error, results, fields) {
connection.release();
if(error) {
if (callback) callback(error, null, null);
return;
}
if (callback) callback(false, results, fields);
});
});
};
module.exports = sql;
My VPS is running fine, my SQL server is running fine as well. I'm not sure what's causing the problem.
My current solution is running a cronjob every 30 minutes to restart the application, I'm not sure if this is a good practice or not.

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 handle a full pool of mysql connections in nodejs

In my Node script I use MySQL and to be able to handle multiple connections I use a connection pool.
Today I forgot to release a connection in the mysql pool. It took me a long time to figure out what the problem was because there was no error shown anywhere.
My code:
const mysql = require('mysql');
const pool = mysql.createPool({
host : 'x',
user : 'x',
password : '#x',
database : 'x',
connectionLimit: 2
});
function executeQuery(){
pool.getConnection((err, connection) => {
if(err) console.log(err);
let query = mysql.format("SELECT * FROM users WHERE id = ?", 1);
connection.query(query, (err, rows) => {
if(err) console.log(err);
console.log(rows);
});
});
}
executeQuery(); // outputs the user as expected
executeQuery(); // outputs the user as expected
executeQuery(); // there is no output in the console, it just looks like nothing happened
My question: How to find out if there are still connections available and if there are no connection available anymore show an error or handle it in a different way?
You forgot to release your connection:
function executeQuery(){
pool.getConnection((err, connection) => {
if(err) console.log(err);
connection.query("SELECT * FROM users WHERE id = ?", [ 1 ], (err, rows) => {
connection.release(); // Give it back or else it gets lost
if(err) console.log(err);
console.log(rows);
});
});
}
There's also no reason to grab the connection like that, you can just use the pool:
function executeQuery() {
pool.query("SELECT * FROM users WHERE id = ?", [ 1 ], (err, connection) => {
if(err) console.log(err);
console.log(rows);
});
}

MySQL super slow query after 3 attempts

I am making a Discord Level Bot, the bot will insert a random amount of XP each time a user's typed a message in the chat. To see a user's level I have a !level command. Like this :
sql.query(`SELECT * FROM WMembers where DiscordID = ${message.author.id}`, (err, rows) => {
if(err) console.log(err)
if(!rows[0]) return message.channel.send("The user has no XP!")
let xp = rows[0].XP
let level = rows[0].Level
let nextLevel = level * 40
message.channel.send(**Level: **${level - 1}\n**Points: **${xp} / ${nextLevel}`)
})
However, when I call the command more than 2-3 times,the queries start executing extremely slowly, taking 5 minutes to finally return the value.
Here is my sql code :
const pool = mysql.createPool({
host : keys.dbHost,
port : 3306,
user : keys.dbUser,
password: keys.dbPass,
database: keys.dbName
});
let sql = {};
sql.query = function(query, params, callback) {
pool.getConnection(function(err, connection) {
if(err) {
if (callback) callback(err, null, null);
return;
}
connection.query(query, params, function(error, results, fields) {
connection.release();
if(error) {
if (callback) callback(error, null, null);
return;
}
if (callback) callback(false, results, fields);
});
});
};
If someone can help me, I will greatly appreciate it. Thank you.
you clearly don't have enough memory for your database: https://dev.mysql.com/doc/mysql-monitor/4.0/en/system-prereqs-reference.html
MySQL's minimum requirements dictate 2GB of memory. you won't get far with 128MB. On that note, just like it has been adviced by #ExploitFate, limiting the number of connections your application can make to the database will also save you some memory

I can't call query after a while in a React Native project that uses MySQL

In my project, I access the MySQL database. I can call and run queries in this database through the program. However, after a while, the called queries become dysfunctional or not called at all.
The example run of the queries:
When I investigated my problem, I found a solution that I needed to increase the maximum number of connections. However, even if I used it, there was no change.
I tried this code: SET GLOBAL max_connections = 150; from this source.
The connection part via node.js:
const connection = mysql.createPool({
host : '192.168.1.101',
user : 'db_manager',
password : '...',
database : 'venue_recommendation'
});
const app = express();
app.get('/venues', function (req, res) {
let sQuery = "SELECT * FROM mekanlar WHERE mekanlar.mahalle_no=\""+req.query.neig+"\" AND mekanlar.puan >="+req.query.star+" AND mekanlar.fiyat <="+req.query.price+";"
console.log(">>>>>",sQuery)
connection.getConnection(function (err, connection) {
if(err) throw err;
connection.query(sQuery, function (error, results, fields) {
if (error) throw error;
res.send(results);
});
});
});
app.get('/Cuisines', function (req, res) {
let sQuery = "SELECT * FROM mutfaklar;"
console.log(">>>>>",sQuery)
connection.getConnection(function (err, connection) {
if(err) throw err;
connection.query(sQuery, function (error, results, fields) {
if (error) throw error;
res.send(results);
});
});
});

Node.js MySQL Needing Persistent Connection

I need a persistent MySQL connection for my Node web app. The problem is that this happens about a few times a day:
Error: Connection lost: The server closed the connection.
at Protocol.end (/var/www/n/node_modules/mysql/lib/protocol/Protocol.js:73:13)
at Socket.onend (stream.js:79:10)
at Socket.EventEmitter.emit (events.js:117:20)
at _stream_readable.js:895:16
at process._tickCallback (node.js:415:13)
error: Forever detected script exited with code: 8
error: Forever restarting script for 2 time
info: socket.io started
Here is my connection code:
// Yes I know multipleStatements can be dangerous in the wrong hands.
var sql = mysql.createConnection({
host: 'localhost',
user: 'my_username',
password: 'my_password',
database: 'my_database',
multipleStatements: true
});
sql.connect();
function handleDisconnect(connection) {
connection.on('error', function(err) {
if (!err.fatal) {
return;
}
if (err.code !== 'PROTOCOL_CONNECTION_LOST') {
throw err;
}
console.log('Re-connecting lost connection: ' + err.stack);
sql = mysql.createConnection(connection.config);
handleDisconnect(sql);
sql.connect();
});
}
handleDisconnect(sql);
As you can see, the handleDisconnect code does not work..
Use the mysql connection pool. It will reconnect when a connection dies and you get the added benefit of being able to make multiple sql queries at the same time. If you don't use the database pool, your app will block database requests while waiting for currently running database requests to finish.
I usually define a database module where I keep my queries separate from my routes. It looks something like this...
var mysql = require('mysql');
var pool = mysql.createPool({
host : 'example.org',
user : 'bob',
password : 'secret'
});
exports.getUsers = function(callback) {
pool.getConnection(function(err, connection) {
if(err) {
console.log(err);
callback(true);
return;
}
var sql = "SELECT id,name FROM users";
connection.query(sql, [], function(err, results) {
connection.release(); // always put connection back in pool after last query
if(err) {
console.log(err);
callback(true);
return;
}
callback(false, results);
});
});
});
I know this is super delayed, but I've written a solution to this that I think might be a bit more generic and usable. I had written an app entirely dependent on connection.query() and switching to a pool broke those calls.
Here's my solution:
var mysql = require('mysql');
var pool = mysql.createPool({
host : 'localhost',
user : 'user',
password : 'secret',
database : 'test',
port : 3306
});
module.exports = {
query: function(){
var sql_args = [];
var args = [];
for(var i=0; i<arguments.length; i++){
args.push(arguments[i]);
}
var callback = args[args.length-1]; //last arg is callback
pool.getConnection(function(err, connection) {
if(err) {
console.log(err);
return callback(err);
}
if(args.length > 2){
sql_args = args[1];
}
connection.query(args[0], sql_args, function(err, results) {
connection.release(); // always put connection back in pool after last query
if(err){
console.log(err);
return callback(err);
}
callback(null, results);
});
});
}
};
This instantiates the pool once, then exports a method named query. Now, when connection.query() is called anywhere, it calls this method, which first grabs a connection from the pool, then passes the arguments to the connection. It has the added effect of grabbing the callback first, so it can callback any errors in grabbing a connection from the pool.
To use this, simply require it as module in place of mysql. Example:
var connection = require('../middleware/db');
function get_active_sessions(){
connection.query('Select * from `sessions` where `Active`=1 and Expires>?;', [~~(new Date()/1000)], function(err, results){
if(err){
console.log(err);
}
else{
console.log(results);
}
});
}
This looks just like the normal query, but actually opens a pool and grabs a connection from the pool in the background.
In response to #gladsocc question:
Is there a way to use pools without refactoring everything? I have
dozens of SQL queries in the app.
This is what I ended up building. It's a wrapper for the query function. It will grab the connection, do the query, then release the connection.
var pool = mysql.createPool(config.db);
exports.connection = {
query: function () {
var queryArgs = Array.prototype.slice.call(arguments),
events = [],
eventNameIndex = {};
pool.getConnection(function (err, conn) {
if (err) {
if (eventNameIndex.error) {
eventNameIndex.error();
}
}
if (conn) {
var q = conn.query.apply(conn, queryArgs);
q.on('end', function () {
conn.release();
});
events.forEach(function (args) {
q.on.apply(q, args);
});
}
});
return {
on: function (eventName, callback) {
events.push(Array.prototype.slice.call(arguments));
eventNameIndex[eventName] = callback;
return this;
}
};
}
};
And I use it like I would normally.
db.connection.query("SELECT * FROM `table` WHERE `id` = ? ", row_id)
.on('result', function (row) {
setData(row);
})
.on('error', function (err) {
callback({error: true, err: err});
});