Skip to content

Commit

Permalink
DNS and load balancing improvements (#130)
Browse files Browse the repository at this point in the history
* Improve hydra initialization process

* Update tests

* Support for JSON via HYDRA_SERVICE env var

* Improved metrics and handling of messages with missing header.

* DNS and load balancing improvements

* Updated test to account for new server instanceID change
  • Loading branch information
cjus authored May 30, 2017
1 parent b651028 commit 32d4a5a
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 32 deletions.
58 changes: 38 additions & 20 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Promise.series = (iterable, action) => {

const EventEmitter = require('events');
const util = require('util');
const uuid = require('uuid');
const Route = require('route-parser');

const Utils = require('./lib/utils');
Expand Down Expand Up @@ -235,7 +236,9 @@ class Hydra extends EventEmitter {
reject(new Error('No Redis connection'));
return;
}
return this._parseServicePortConfig(this.config.servicePort).then((port) => {

let p = this._parseServicePortConfig(this.config.servicePort);
p.then((port) => {
this.config.servicePort = port;
this.serviceName = config.serviceName;
if (this.serviceName && this.serviceName.length > 0) {
Expand All @@ -244,27 +247,42 @@ class Hydra extends EventEmitter {
this.serviceDescription = this.config.serviceDescription || 'not specified';
this.config.serviceVersion = this.serviceVersion = this.config.serviceVersion || this._getParentPackageJSONVersion();

// if serviceIP field contains a name rather than a dotted IP address
// then use DNS to resolve the name to an IP address.
const dns = require('dns');
const net = require('net');
if (this.config.serviceIP && this.config.serviceIP !== '' && net.isIP(this.config.serviceIP) === 0) {
dns.lookup(this.config.serviceIP, (err, result) => {
this.config.serviceIP = result;
this._updateInstanceData();
ready();
});
} else if (!this.config.serviceIP || this.config.serviceIP === '') {
let ip = require('ip');
this.config.serviceIP = ip.address();
/**
* Determine network DNS/IP for this service.
* - First check whether serviceDNS is defined. If so, this is expected to be a DNS entry.
* - Else check whether serviceIP exists and is not empty ('') and is not an segemented IP
* such as 192.168.100.106 If so, then use DNS lookup to determine an actual dotted IP address.
* - Else check whether serviceIP exists and *IS* set to '' - that means the service author is
* asking Hydra to determine the machine's IP address.
* - And final else - the serviceIP is expected to be populated with an actual dotted IP address
* or serviceDNS contains a valid DNS entry.
*/
if (this.config.serviceDNS && this.config.serviceDNS !== '') {
this.config.serviceIP = this.config.serviceDNS;
this._updateInstanceData();
ready();
} else {
this._updateInstanceData();
ready();
const net = require('net');
if (this.config.serviceIP && this.config.serviceIP !== '' && net.isIP(this.config.serviceIP) === 0) {
const dns = require('dns');
dns.lookup(this.config.serviceIP, (err, result) => {
this.config.serviceIP = result;
this._updateInstanceData();
ready();
});
} else if (!this.config.serviceIP || this.config.serviceIP === '') {
let ip = require('ip');
this.config.serviceIP = ip.address();
this._updateInstanceData();
ready();
} else {
this._updateInstanceData();
ready();
}
}
return 0;
}).catch((err) => reject(err));
return p;
}).catch((err) => reject(err));
});
}
Expand Down Expand Up @@ -388,7 +406,9 @@ class Hydra extends EventEmitter {
* @return {string} instance id
*/
_serverInstanceID() {
return Utils.md5Hash(`${this.config.serviceIP}:${this.config.servicePort}`);
return uuid.
v4().
replace(RegExp('-', 'g'), '');
}

/**
Expand Down Expand Up @@ -900,9 +920,7 @@ class Hydra extends EventEmitter {
reject(new Error(msg));
} else {
if (result.length > 1) {
result.sort((a, b) => {
return (a.updatedOnTS < b.updatedOnTS) ? 1 : ((b.updatedOnTS < a.updatedOnTS) ? -1 : 0);
});
Utils.shuffeArray(result);
}
resolve(result);
}
Expand Down
2 changes: 1 addition & 1 deletion lib/server-request.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const http = require('http');
const REQUEST_TIMEOUT = 5 * 1000; // 5-seconds
const REQUEST_TIMEOUT = 30000; // 30-seconds

/**
* @name ServerRequest
Expand Down
12 changes: 12 additions & 0 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,18 @@ class Utils {
return (new RegExp(uuidPattern)).test(str);
}

/**
* @name shuffeArray
* @summary shuffle an array in place
* @param {array} a - array elements may be numbers, string or objects.
* @return {undefined}
*/
static shuffeArray(a) {
for (let i = a.length; i; i--) {
let j = Math.floor(Math.random() * i);
[a[i - 1], a[j]] = [a[j], a[i - 1]];
}
}
}

module.exports = Utils;
11 changes: 2 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@
{
"name": "hydra",
"version": "1.4.6",
"version": "1.4.7",
"license": "MIT",
"author": "Carlos Justiniano",
"contributors": [
"Artem Kochnev <[email protected]>",
"Carlos Justiniano <[email protected]>",
"Eric Adum <[email protected]>",
"Jedediah Smith <[email protected]>",
"Rolando Santamaria Maso <[email protected]>",
"Sebastiansch <[email protected]>"
],
"contributors": "https://github.com/flywheelsports/hydra/graphs/contributors",
"description": "Hydra is a NodeJS light-weight library for building distributed computing applications such as microservices",
"keywords": [
"hydra",
Expand Down
2 changes: 0 additions & 2 deletions specs/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,6 @@ describe('Hydra', function() {
expect(err).to.be.null;
expect(data.length).to.equal(3);
expect(data).to.include('hydra:service:test-service:service');
expect(data).to.include('hydra:service:test-service:73909f8c96a9d08e876411c0a212a1f4:presence');
expect(data).to.include('hydra:service:nodes');
done();
});
Expand All @@ -175,7 +174,6 @@ describe('Hydra', function() {
expect(serviceInfo.serviceName).to.equal('test-service');
expect(serviceInfo.serviceIP).to.equal('127.0.0.1');
expect(serviceInfo.servicePort).to.equal('5000');
expect(hydra.getInstanceID()).to.equal('73909f8c96a9d08e876411c0a212a1f4');
done();
});
});
Expand Down

0 comments on commit 32d4a5a

Please sign in to comment.