0
\$\begingroup\$

I wrote connection logic for a wrapper around RethinkDB in node.js. While it works, I know it can be cleaned up, and done in a better manner. Essentially the logic is start at the first host in config.hosts, if _connect() fails, then try the next host in the array. This continues for three times, or until config.hosts is empty. If __connect() is successful just set rethinkdbConnection to the returned connection object.

var config.hosts = ['10.0.0.1', '10.0.0.2', '10.0.0.3'];
var rethinkdbConnection;

exports.connect = function(config, callback) {
    var rethinkdbConfig = clone(config);
    delete rethinkdbConfig.hosts;

    function _connect(callback) {
        rethinkdbConfig.host = config.hosts.shift();

        r.connect(rethinkdbConfig, function(error, connection) {
            if(error) {
                return callback(error);
            }

            return callback(null, connection);
        });
    }

    _connect(function(error, connection) {
        if(error) {
            if(!config.hosts.length) {
                return callback(error);
            }

            _connect(function(error, connection) {
                if(error) {
                    if(!config.hosts.length) {
                        return callback(error);
                    }

                    _connect(function(error, connection) {
                        if(error) {
                            return callback(error);
                        }
                    });
                }
            });
        } else {
            rethinkdbConnection = connection;
            return callback();
        }
    });
};

What is a better way to write this?

Also it would be great instead of arbitrarily trying _connet() 3 times, to try as many times as the length of config.hosts instead.

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

You can use recursive promises. If promises don't exist in your platform, you could use a third party library or a polyfill to do the same thing.

function tryConnecting(config, remainingHosts){

    // Make a copy of hosts that we can shift off stuff. Don't modify config.
    remainingHosts = config.hosts.slice(0);

    // Promises resolve or reject only when we call resolve and recject.
    // When we see that we can still retry, we don't call either.
    return new Promise(function(resolve, reject)){

        // Update host
        config.host = remainingHosts.shift();

        // Try connecting
        r.connect(config, function(error, connection) {

            // If it fails and we still have hosts remaining, call the function
            // again. This promise's resolve and reject will be called when that
            // call's promise resolves or rejects
            if(error && remainingHosts.length) tryConnecting(config, remainingHosts).then(resolve, reject);

            // If it's an error, and we have no more remaining hosts, we reject
            // the promise. If this call was not the first (ie. previous call
            // failed with remaining hosts), then that promise will be rejected
            // with the same values.
            else if(error && !remainingHosts.length) reject(error, null);

            // If no error, then we resolve with the connection. If this was
            // not the first call (ie. previous call failed with remaining
            // hosts) then, that promise will resolve with the same values.
            else resolve(null, connection);
        });
    });
}

exports.connect = function(config, callback) {
    tryConnecting(config, config.hosts).then(callback, callback);
};
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.