How to change required connection after require()

Issue

In a Node.js project I am currently working on, the MySQL server closes the connection after some idle time. I implemented an error-handler which reconnects after this kind of connection loss. The error-handling works but I can’t find a way to get the files which already required the connection before to use the new connection.

I already tried to delete the cache, but this does not resolve my issue.

var mysql = require('mysql');
var mysqlConfig = require('./mysqlConfig');
var connection;

function handleDisconnect() {
    connection = mysql.createConnection(mysqlConfig.db);

    connection.connect((err) => {
        if (err) {
            console.log("error on connection to Database: " + err);
            setTimeout(handleDisconnect, 1000);
        }
    });

    connection.on('error', (err) => {
        delete require.cache[require.resolve('./db.js')]; //this module
        if (err.code === 'PROTOCOL_CONNECTION_LOST') {
            handleDisconnect();
        } else {
            throw err;
        }
    });
}

handleDisconnect();

module.exports = connection;

Here is an example of a file where this module is required:

var db = require('../db');
var connector = {};

connector.GetStuff = function(query) {
    return new Promise((resolve, reject) => {
        let response = {};
        db.query(query, (error, results, fields) => {
            if (error) throw error;
            if (results && results.length > 1) {
                response = results[0];
                resolve(response);
            }
        })
    })
}

Id like to just replace the connection objects, which were required before with the new one. But actually my application crashes with following error:

Error: Cannot enqueue Query after fatal error.

Please don’t tell me to just open up a new connection for each query. this is a concept I can not use because of the customers wish.

Solution

A good solution would be to export not the very connection object in the first file, but some wrapper or container, contents of which are periodically updated by your connection fault handler function.

class ConnectionContainer {
  setConnection(connection) {
    this.connection = connection;
  }

  getCurrentConnection() {
    return this.connection;
  }
}

const connectionContainer = new ConnectionContainer();

function handleDisconnect() {
    const connection = mysql.createConnection(mysqlConfig.db);

    connection.connect((err) => {
        if (err) {
            console.log("error on connection to Database: " + err);
            return setTimeout(handleDisconnect, 1000);
        } else {
          container.setConnection(connection); // set a new connection once it's connected
        }
    });

    connection.on('error', (err) => {
        delete require.cache[require.resolve('./db.js')]; // I don't think you need this anymore
        if (err.code === 'PROTOCOL_CONNECTION_LOST') {
            handleDisconnect();
        } else {
            throw err;
        }
    });
}

handleDisconnect();

module.exports.connectionContainer = connectionContainer;

// and in the connector file you could go like this:

const { connectionContainer } = require('../db'); // you might need a better name here for the file

//...
connectionContainer.getCurrentConnection().query(query, () => {});

Answered By – Vladyslav Usenko

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published