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.
1 Answer 1
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);
};