nodejs - Error de reproducción de MySQL: el servidor cerró la conexión(node.js)
nom mysql (5)
Estoy intentando reproducir un error de MySQL que estoy viendo en mi aplicación node.js en EC2 con la biblioteca mysql de nodo :
Conexión perdida: el servidor cerró la conexión.
No puedo reproducir el error de forma local. Matar la base de datos se maneja bien con mi código; simplemente vuelve a verificar cada pocos segundos y se vuelve a conectar a la base de datos una vez que se reinicia. En EC2, ocurre alrededor de las 4 am del Pacífico, pero la base de datos todavía está funcionando bien.
me gustaría
- Reproduce el crash con mi mysql local
- Agregue la lógica que necesito en mi módulo mysql helper para manejar esto
Aquí está el error en mi aplicación node.js:
2012-10-22T08: 45: 40.518Z - error: uncaughtException date = Mon Oct 22 2012 08:45:40 GMT + 0000 (UTC), pid = 14184, uid = 0, gid = 0, cwd = / home / ec2 -user / my-app, execPath = / usr / bin / nodejs, version = v0.6.18, argv = [/ usr / local / bin / node, /home/ec2-user/my-app/app.js, - -my-app], rss = 15310848, heapTotal = 6311392, heapUsed = 5123292, loadavg = [0.0029296875, 0.0146484375, 0.04541015625], tiempo de actividad = 3238343.511107486, trace = [column = 13, file = / home / ec2 / My User] app / node_modules / mysql / lib / protocol / Protocol.js, function = Protocol.end, line = 63, method = end, native = false, column = 10, file = stream.js, function = Socket.onend, line = 80, method = onend, native = false, column = 20, file = events.js, function = Socket.emit, line = 88, method = emit, native = false, column = 51, file = net.js, function = TCP.onread, line = 388, method = onread, native = false], stack = [Error: Conexión perdida: el servidor cerró la conexión.,
en Protocol.end (/home/ec2-user/my-app/node_modules/mysql/lib/protocol/Protocol.js:63:13), en Socket.onend (stream.js: 80: 10), en Socket. emit (events.js: 88: 20), en TCP.onread (net.js: 388: 51)]
Aquí está mi código (módulo de ayuda mysql):
module.exports = function (conf,logger) {
var mysql = require(''mysql'');
var connectionState = false;
var connection = mysql.createConnection({
host: conf.db.hostname,
user: conf.db.user,
password: conf.db.pass,
database: conf.db.schema,
insecureAuth: true
});
function attemptConnection(connection) {
if(!connectionState){
connection = mysql.createConnection(connection.config);
connection.connect(function (err) {
// connected! (unless `err` is set)
if (err) {
logger.error(''mysql db unable to connect: '' + err);
connectionState = false;
} else {
logger.info(''mysql connect!'');
connectionState = true;
}
});
connection.on(''close'', function (err) {
logger.error(''mysqldb conn close'');
connectionState = false;
});
connection.on(''error'', function (err) {
logger.error(''mysqldb error: '' + err);
connectionState = false;
/*
if (!err.fatal) {
return;
}
if (err.code !== ''PROTOCOL_CONNECTION_LOST'') {
throw err;
}
*/
});
}
}
attemptConnection(connection);
var dbConnChecker = setInterval(function(){
if(!connectionState){
logger.info(''not connected, attempting reconnect'');
attemptConnection(connection);
}
}, conf.db.checkInterval);
return connection;
};
Echa un vistazo a la característica de la piscina mysql en node-mysql
var mysql = require(''mysql'');
var pool = mysql.createPool({
host : ''example.org'',
user : ''bob'',
password : ''secret''
});
pool.getConnection(function(err, connection) {
// connected! (unless `err` is set)
connection.end();
});
Estaba teniendo problemas similares y creé una función de envoltura getConnection () que verifica el estado de la conexión mysql antes de devolverla a la persona que llama y restablece la conexión según sea necesario. En mis pruebas, ha manejado los problemas de conexión fatales y no fatales de manera transparente para la aplicación. Si la conexión simplemente se agotó, la aplicación se recupera sin experimentar ningún error. Si hay un problema de conexión de base de datos transitorio pero fatal, la aplicación volverá a funcionar automáticamente tan pronto como la conectividad de la base de datos vuelva a estar disponible.
En cuanto a reproducir el problema para la prueba, agregue las siguientes dos líneas al archivo my.ini o my.cnf bajo el bloque [mysqld]
:
interactive_timeout=30
wait_timeout=30
Aquí está el contenido de un archivo que he llamado "database.js":
var mysql = require("mysql");
var CONFIG = require(__dirname + "/configuration");
module.exports.getConnection = function() {
// Test connection health before returning it to caller.
if ((module.exports.connection) && (module.exports.connection._socket)
&& (module.exports.connection._socket.readable)
&& (module.exports.connection._socket.writable)) {
return module.exports.connection;
}
console.log(((module.exports.connection) ?
"UNHEALTHY SQL CONNECTION; RE" : "") + "CONNECTING TO SQL.");
var connection = mysql.createConnection({
host : CONFIG.db.host,
user : CONFIG.db.user,
password : CONFIG.db.password,
database : CONFIG.db.database,
port : CONFIG.db.port
});
connection.connect(function(err) {
if (err) {
console.log("SQL CONNECT ERROR: " + err);
} else {
console.log("SQL CONNECT SUCCESSFUL.");
}
});
connection.on("close", function (err) {
console.log("SQL CONNECTION CLOSED.");
});
connection.on("error", function (err) {
console.log("SQL CONNECTION ERROR: " + err);
});
module.exports.connection = connection;
return module.exports.connection;
}
// Open a connection automatically at app startup.
module.exports.getConnection();
// If you''ve saved this file as database.js, then get and use the
// connection as in the following example:
// var database = require(__dirname + "/database");
// var connection = database.getConnection();
// connection.query(query, function(err, results) { ....
Esto es lo que terminé usando, y funcionó bastante bien. En la conexión ocasional perdida / reinicio se recuperó muy bien. Tengo un archivo database.js que establece conexiones y las verifica periódicamente.
Para hacer una petición:
var conn = require(''./database'');
var sql = ''SELECT foo FROM bar;'';
conn.query(sql, [userId, plugId], function (err, rows) {
// logic
}
Aquí está mi base de datos.js
var mysql = require(''mysql'');
var Common = require(''./common'');
var conf = Common.conf;
var logger = Common.logger;
var connectionState = false;
var connection = mysql.createConnection({
host: conf.db.hostname,
user: conf.db.user,
password: conf.db.pass,
database: conf.db.schema,
insecureAuth: true
});
connection.on(''close'', function (err) {
logger.error(''mysqldb conn close'');
connectionState = false;
});
connection.on(''error'', function (err) {
logger.error(''mysqldb error: '' + err);
connectionState = false;
});
function attemptConnection(connection) {
if(!connectionState){
connection = mysql.createConnection(connection.config);
connection.connect(function (err) {
// connected! (unless `err` is set)
if (err) {
logger.error(''mysql db unable to connect: '' + err);
connectionState = false;
} else {
logger.info(''mysql connect!'');
connectionState = true;
}
});
connection.on(''close'', function (err) {
logger.error(''mysqldb conn close'');
connectionState = false;
});
connection.on(''error'', function (err) {
logger.error(''mysqldb error: '' + err);
if (!err.fatal) {
//throw err;
}
if (err.code !== ''PROTOCOL_CONNECTION_LOST'') {
//throw err;
} else {
connectionState = false;
}
});
}
}
attemptConnection(connection);
var dbConnChecker = setInterval(function(){
if(!connectionState){
logger.info(''not connected, attempting reconnect'');
attemptConnection(connection);
}
}, conf.db.checkInterval);
// Mysql query wrapper. Gives us timeout and db conn refreshal!
var queryTimeout = conf.db.queryTimeout;
var query = function(sql,params,callback){
if(connectionState) {
// 1. Set timeout
var timedOut = false;
var timeout = setTimeout(function () {
timedOut = true;
callback(''MySQL timeout'', null);
}, queryTimeout);
// 2. Make query
connection.query(sql, params, function (err, rows) {
clearTimeout(timeout);
if(!timedOut) callback(err,rows);
});
} else {
// 3. Fail if no mysql conn (obviously)
callback(''MySQL not connected'', null);
}
}
// And we present the same interface as the node-mysql library!
// NOTE: The escape may be a trickier for other libraries to emulate because it looks synchronous
exports.query = query;
exports.escape = connection.escape;
La solución es utilizar la conexión de pooling!
Puedes escribir código para manejar la conexión manualmente, funciona. Sin embargo, la agrupación es un diseño para esto, use la conexión de agrupación solucionada error de caída de conexión.
var mysql = require(''mysql'');
var pool = mysql.createPool({
connectionLimit : 10,
host : ''example.org'',
user : ''bob'',
password : ''secret'',
database : ''my_db''
});
pool.query(''SELECT 1 + 1 AS solution'', function (error, results, fields) {
if (error) throw error;
console.log(''The solution is: '', results[0].solution);
});
Usando generic-pool , escribí algo que funciona localmente. Supongo que lo probaré y veré si no se bloquea de manera extraña en el lado del servidor.
// Test node connection pool stuff
// Create a MySQL connection pool with
// a max of 10 connections, a min of 2, and a 30 second max idle time
var poolModule = require(''generic-pool'');
var pool = poolModule.Pool({
name : ''mysql'',
create : function(callback) {
var Client = require(''mysql'').Client; // use node-mysql library in all it''s dubious glory
var c = new Client();
c.user = ''root'';
c.password = ''xxx'';
c.database = ''test'';
c.on(''close'', function (err) {
console.log(''mysqldb conn close'');
});
c.on(''error'', function (err) {
console.log(''mysqldb error: '' + err);
});
// parameter order: err, resource
// new in 1.0.6
callback(null, c);
},
destroy : function(client) { client.end(); },
max : 10,
// optional. if you set this, make sure to drain() (see step 3)
min : 2,
// specifies how long a resource can stay idle in pool before being removed
idleTimeoutMillis : 30000,
// if true, logs via console.log - can also be a function
log : true
});
var http = require(''http'');
http.createServer(function (req, res) {
// Get db conn
pool.acquire(function(err, client) {
if (err) {
// handle error - this is generally the err from your
// factory.create function
console.log(''pool.acquire err: '' + err);
res.writeHead(500, {''Content-Type'': ''application/json''});
out = {
err: err
}
res.end(JSON.stringify(out));
}
else {
client.query("select * from foo", [], function(err, results) {
if(err){
res.writeHead(500, {''Content-Type'': ''application/json''});
out = {
err: err
}
res.end(JSON.stringify(out));
} else {
res.writeHead(500, {''Content-Type'': ''application/json''});
out = {
results: results
}
res.end(JSON.stringify(out));
}
// return object back to pool
pool.release(client);
});
}
});
}).listen(9615);
¡Bastante por favor no mueras a las 4am sin ninguna razón aparente!