3

I am connecting my node to mysql using the below code for all my rest apis which i am using in my project; i have put this as a common db connecting file for all my query request.

var mysql = require('mysql');
var db_connect = (function () {
    function db_connect() {
        mysqlConnConfig = {
            host: "localhost",
            user: "username",
            password: "password",
            database: "db_name"
        };
    }
    db_connect.prototype.unitOfWork = function (sql) {
    mysqlConn = mysql.createConnection(mysqlConnConfig);
        try {
            sql(mysqlConn);
        } catch (ex) {

            console.error(ex);
        } finally {
            mysqlConn.end();
        }
    };
    return db_connect;
})();
exports.db_connect = db_connect;

The above code works fine and i will use my query for execution with the 'sql' as below in all of my rest api as below.

var query1 = "SELECT * FROM table1";
 sql.query(query1,function(error,response){
if(error){
    console.log(error);
}
else{
    console.log(response);
    }
 })

everything goes good till now but the problem is i am getting the sql protocol connection error after 8-12 hours of running my forever module

forever start app.js

i am starting my project with the above forever module. after 8-12 hours i am getting the below error and all my rest api are not working or going down.

"stack": ["Error: Connection lost: The server closed the connection.", "    at Protocol.end (/path/to/my/file/node_modules/mysql/lib/protocol/Protocol.js:109:13)", "    at Socket.<anonymous> (/path/to/my/file/node_modules/mysql/lib/Connection.js:102:28)", "    at emitNone (events.js:72:20)", "    at Socket.emit (events.js:166:7)", "    at endReadableNT (_stream_readable.js:913:12)", "    at nextTickCallbackWith2Args (node.js:442:9)", "    at process._tickDomainCallback (node.js:397:17)"],
"level": "error",
"message": "uncaughtException: Connection lost: The server closed the connection.",
"timestamp": "2017-09-13T21:22:25.271Z"

Then i got a solution in my research to configure for handle disconnection as below. But i am struggling to configure my sql connection as below with my code.

var db_config = {
  host: 'localhost',
    user: 'root',
    password: '',
    database: 'example'
};

var connection;

function handleDisconnect() {
  connection = mysql.createConnection(db_config); // 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();

can anyone help me in altering my code with the above code?

Jagadeesh
  • 1,967
  • 8
  • 24
  • 47

2 Answers2

1
SHOW SESSION VARIABLES LIKE '%wait_timeout';
SHOW GLOBAL  VARIABLES LIKE '%wait_timeout';

One of them is set to 28800 (8 hours). Increase it.

Or... Catch the error and reconnect.

Or... Check on how "connection pooling" is handled in your framework.

But... Be aware that network glitches can occur. So, simply increasing the timeout won't handle such glitches.

Or... Don't hang onto a connection so long. It it not playing nice. And it could lead to exceeding max_connections.

(Sorry, I don't understand your application well enough to be more specific about which of these many paths to pursue.)

max_connections

...wait_timeout and max_connections go together in a clumsy way. If the timeout is "too high", the number of connections can keep growing, thereby threatening "too many connections" error. In typical designs, it is better to lower the timeout to prevent clients from wastefully hanging onto a connection for too long.

If your situation is this: "Fixed number of clients that want to stay connected forever", then increase the timeout, but not max_connections (at least not much beyond the fixed number of clients).

Still, if the network hiccups, the connections could break. So, you can still get "connection lost". (However, if everything is on the same machine, this is rather unlikely.)

Rick James
  • 135,179
  • 13
  • 127
  • 222
  • is increasing those timeout will give any other bug? – Jagadeesh Sep 19 '17 at 05:27
  • do you think that will be the reason for my problem? – Jagadeesh Sep 19 '17 at 05:29
  • added a discussion of max_connections – Rick James Sep 19 '17 at 13:40
  • now i have increased my timeout to 1 year and querying my database every 5 seconds and this issue is not raised again? is that a good practice? – Jagadeesh Sep 21 '17 at 03:58
  • @Jagadeesh " increased my timeout to 1 year", i don't think it's a good idea, MySQL will hold too much "Sleep" connections and MySQL may reach the max_connections if your code doesn't close connections somewhere; "querying my database every 5 seconds" is a good idea, it act as a heartbeat, so MySQL will not close the "Sleep" connections; Root case of connect problems is Network issues or Timeout issues mostly, in my opinion; – Wang Wen'an Sep 21 '17 at 07:29
  • so what should i change? the timeout or querying for seconds? – Jagadeesh Sep 21 '17 at 07:31
  • or suggest me the best way to close the connection. – Jagadeesh Sep 21 '17 at 07:31
  • 1
    @Jagadeesh I think "querying my database every 5 seconds" is enough, it act as a heartbeat and MySQL will not close the connections, just leave the wait_timeout as defaults; – Wang Wen'an Sep 21 '17 at 07:51
  • or whatif i restart my project evryday once with cron? will this help me? – Jagadeesh Sep 21 '17 at 07:57
  • @GreenBlade restarting my project every day once can with the cron could help me? – Jagadeesh Sep 21 '17 at 08:21
  • @Jagadeesh Restart the project every day and set MySQL wait_timeout more than one day can help you; The error occurs because your project uses the expired connections(didn't have any activities in 8 hours), restart the project will create new connection to MySQL, and set the wait_timeout more than one day tells MySQL not to disconnect the connections your project holds; – Wang Wen'an Sep 21 '17 at 08:29
  • and finally tell me one thing .. i have to change wait_timeout or interactive_wait_timeout and those values are in seconds or milliseconds? Then if i type show processlist in my db there are list of connections with the time column. what is the maximum time for that? – Jagadeesh Sep 21 '17 at 08:35
  • Restarting will break the connections. Why do you need the restart; are you running on Windows? – Rick James Sep 21 '17 at 13:25
  • The timeout values are in seconds. `interactive...` is mostly for the mysql commandline tool, not for Java/Perl/PHP/etc. The `Time` column is how long the _current_ SQL has been running or how long (in seconds) the connection has been `Sleeping`. – Rick James Sep 21 '17 at 13:28
0

I have sloved this problem by using pool connection. Try it in this way https://www.npmjs.com/package/mysql

var mysql = require('mysql');
var pool  = mysql.createPool(...);
 
pool.getConnection(function(err, connection) {
  // Use the connection 
  connection.query('SELECT something FROM sometable', function (error, results, fields) {
    // And done with the connection. 
    connection.release();
 
    // Handle error after the release. 
    if (error) throw error;
 
    // Don't use the connection here, it has been returned to the pool. 
  });
});
Denis Lisitskiy
  • 1,285
  • 11
  • 15