I am writing a nodejs application and want to use connection pooling.
However, the following application does not terminate - although I would expect it to terminate after the call to connection.end()
Application works just fine, if I use one connection instead of the pool. Do I need to terminate the pool in some way?
Library used: https://github.com/felixge/node-mysql
node.js version: 0.10.4 on Ubuntu
var mysql = require('mysql');
var pool = mysql.createPool({
host : 'example.org',
user : 'myuser',
password : 'youbet',
database : 'notrevealingdetails',
insecureAuth: true
});
function getCampaignData(callback)
{
pool.getConnection(function(err, connection) {
if(err) throw err;
connection.query(
'SELECT cam.id, cam.name AS campaign_name, cam.subdomain, usr.email, usr.display_name AS user_displayname ' +
'FROM campaigns AS cam INNER JOIN users AS usr ON usr.id = cam.user_id ' +
'WHERE cam.state=2',
function(err, rows) {
callback(err, rows,connection);
//console.log('called end()');
}); // callback function for connection.query
}); // end pool.GetConnection
}
getCampaignData(function(err, rows, connection) {
if (err) throw err;
connection.end();
console.log("I expect my app to terminate");
});
I was having the very same problem, but looking at the source code
https://github.com/felixge/node-mysql/blob/master/lib/Pool.js
I found that the pool, at least in its current implementation, has an end() method that is turns call end() on all connections.
It also accept a callback function to be called after all connections are actually ended (or whenever an error occur).
pool.end(function (err) {
if (err) console.error("An error occurred: " + err);
else console.log("My app terminated");
});
I would use
getCampaignData(function(err, rows, connection)
{
if (err) throw err;
connection.release();
console.log("I expect my app to terminate");
});
Related
I'm facing this error when the there are no requests to mysql it goes to idles state and we face this db error. I'm working with node, mysql deployed onto openshift cluster.
How do I keep the db connection alive such that the server never closes the connection?
PFA
Please, lemme know is there any solutions? I'm stuck for past 2 weeks
Update -
Following is the code I'm using
`var connection;
function handleDisconnect() {
connection = mysql.createConnection({
host: config.db.host,
user: config.db.user,
password: config.db.password,
database: config.db.database,
port: config.db.port,
}); // 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();`
Since, you are using Node.js, you could use the connection pool.
pooling-connections
Below is a snippet from the link. Notice, connection.release(); It doesn't destroy the connection, but allows the connection to be used again.
var mysql = require('mysql');
var pool = mysql.createPool({
connectionLimit : 10,
host : 'example.org',
user : 'bob',
password : 'secret',
database : 'my_db'
});
pool.getConnection(function(err, connection) {
if (err) throw err; // not connected!
// Use the connection
connection.query('SELECT something FROM sometable', function (error, results, fields) {
// When done with the connection, release it.
connection.release();
// Handle error after the release.
if (error) throw error;
// Don't use the connection here, it has been returned to the pool.
});
});
I'm using MySQL on Nodejs. I'm using mysql pool to create the connection:
Var mysqk = require ('mysql');
Var pool = mysql.createPool ({my configs});
My question is:
Where in the app will I use pool.end() as reported in the documentation?
For example: in my www file, I created a code to release other things as I have pointed in de code. Should I use pool.end() there?
var app = require('../app');
var debug = require('debug')('cancela:server');
var http = require('http');
var port = normalizePort(process.env.PORT || '4000');
app.set('port', port);
var server = http.createServer(app);
// my app codes...
..
.
.
process.once('SIGTERM', end);
process.once('SIGINT', end);
function end() {
server.close(function(err){
if(err) throw err();
// Should I end the Pool connection here? <<<<<<===================================
// pool.end(function (err) {
// // all connections in the pool have ended
// });
console.log('Server endded!');
/* exit gracefully */
process.exit();
});
}
Sometimes you want to manually release the connection pool for whatever reasons so you can use pool.end() before eventually recreating the pool.
Most of times you want to release it when your server is about to shutdown so you can do what you are thinking. Pay attention to the location of the function call process.exit(). It must be called after the connection release, otherwise the pool won't finish to release.
function end() {
server.close(function (err) {
if (err) throw err;
console.log('Server endded!');
pool.end(function (err) {
if (err) throw err;
process.exit();
});
});
}
So great part of this is that this same code works on my development machine.
I'm trying to deploy it to the production server, and i'm getting this error:
Cannot call method release of undefined.
This works on my box, so why is that not working in production is what confuses me.
I downloaded the code with all the modules, then tried to do npm install, and still manually deploy express and mysql, but no luck.
The infringing line is:
connection.release();
If i rem that line, then it will just hang on anything trying to call connection.
The code:
process.env.TZ = 'UTC';
var express = require("express");
var mysql = require('mysql');
var pool = mysql.createPool({
connectionLimit : 100, //important
host : 'localhost',
user : 'thedbuser',
password : 'thedbpass',
database : 'thedatabase',
debug : false,
timezone: 'utc'
});
var app = express();
function get_data(req,res) {
pool.getConnection(function(err,connection){
if (err) {
connection.release();
res.json({"code" : 100, "status" : "Error in connection database"});
return;
}
console.log('connected as id ' + connection.threadId);
var id = Number(req.param("id"));
connection.query("select * from thetable WHERE id = ?" , [id], function(err,rows){
connection.release();
if(!err) {
res.json(rows);
}
});
connection.on('error', function(err) {
res.json({"code" : 100, "status" : "Error in connection database"});
return;
});
});
}
app.get("/id",function(req,res){
get_data(req,res);
});
app.listen(3000);
pool.getConnection(function(err,connection){
if (err) {
connection.release();
res.json({"code" : 100, "status" : "Error in connection database"});
return;
}
So inside the if (err) block means there was an error. The node.js generic callback API semantic is when an err is passed to the callback function, the success/result variable is not guaranteed to also be provided. In this case, since there was an error getting a connection, no connection object is passed to the callback - because the error prevented the connection from happening correctly. Thus you can probably safely just delete the connection.release() line but if you know there is a case where both err and connection will both be passed (I suspect there is no such case), you could guard your call to connection.release() with an if (connection) block or a logical operator like connection && connection.release()
code as follows:
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
port :"3306",
database :"mydb",
user : 'root',
password : '007007',
});
var isCon = true;
connection.connect(
function (err) {
console.log(isCon);
if (err) {
isCon=false;
console.error("error connecting :"+err);
return;
};
}
);
if(isCon){
connection.query('select * from tb_items', function(err, result) {
if (err) throw err;
console.log('The solution is: ', result);
console.log('The typeof solution is ',typeof(result));
debugger;
});
connection.end();
}
connection.connect(
function (err) {
console.log(isCon);
if (err) {
isCon=false;
console.error("error connecting :"+err);
return;
};
}
);
if(isCon){
connection.query('select * from tb_items', function(err, result) {
if (err) throw err;
console.log('The solution is: ', result);
console.log('The typeof solution is ',typeof(result));
debugger;
});
connection.end();
}
i just open()-->connect()-->query()-->end(),then did it again,but second time , there is a error : Error:Could not enqueue Handshake after invoking quiting .
question : maybe i can't reopen it after end().but i just wanna kwon ,if i end(),how can i reopen it?
no, you can't, just create another one. All state in the connection class only relevant for current connection, so having "reopenWithSameConfig" method is possible, but you should really do this from outside.
Also, you don't need to close connection on each query - just continue to reuse it without calling .end()
If you want multiple connections and automatic disposal of dead connections you should use Pool class.
One more note: your isCon check is incorrect, connection.query is called before connect() callback so it's always true. It's safe to just check error in query callback itself. If connection was not successful error is propagated to a queued command
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});
});