Skip to content

Commit

Permalink
Plugins (#25)
Browse files Browse the repository at this point in the history
* implemented plugins

* added HydraEvent and HydraPlugin modules

* handle errors during plugin initialization

* added plugins.md with plugin tutorial

* added table of contents to documentation.md
  • Loading branch information
emadum authored Dec 19, 2016
1 parent 57bb243 commit fc3c561
Show file tree
Hide file tree
Showing 6 changed files with 341 additions and 4 deletions.
23 changes: 23 additions & 0 deletions documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,25 @@ In Hydra, a service instance is simply a process which uses Hydra to handle micr

> ☕ For a quick overview of what Hydra offers refer to the end of this document for a list of public methods.
* [Installing Hydra](#installing-hydra)
* [Using Hydra](#using-hydra)
* [Importing Hydra](#importing-hydra)
* [Initialization](#initialization)
* [Hydra modes](#hydra-modes)
* [Service mode](#service-mode)
* [Consumer mode](#consumer-mode)
* [Service Discovery](#service-discovery)
* [Presence](#presence)
* [Health and Presence](#health-and-presence)
* [Using Hydra to monitor services](#using-hydra-to-monitor-services)
* [Messaging](#messaging)
* [Inter-service messaging](#inter-service-messaging)
* [Built-in message channels](#built-in-message-channels)
* [UMF messaging](#umf-messaging)
* [Hydra Methods](#hydra-methods)
* [Hydra Plugins](#hydra-plugins)


# Installing Hydra

To use Hydra from another project:
Expand Down Expand Up @@ -676,3 +695,7 @@ Marks a queued message as either completed or not
*/
markQueueMessage(message, completed, reason)
```
# Hydra plugins
See the [Plugin documentation](/plugins.md).
24 changes: 24 additions & 0 deletions events.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
'use strict';

/**
* @name HydraEvent
* @description EventEmitter event names for Hydra
*/
class HydraEvent {
/**
* @return {string} config update event
* @static
*/
static get CONFIG_UPDATE_EVENT() {
return 'configUpdate';
}
/**
* @return {string} update message type
* @static
*/
static get UPDATE_MESSAGE_TYPE() {
return 'configRefresh';
}
}

module.exports = HydraEvent;
62 changes: 59 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@
'use strict';

const Promise = require('bluebird');
Promise.series = (iterable, action) => {
return Promise.mapSeries(
iterable.map(action),
(value, index, length) => value || iterable[index].name || null
);
};

const EventEmitter = require('events');
const redis = require('redis');
const moment = require('moment');
Expand Down Expand Up @@ -48,19 +55,64 @@ class Hydra extends EventEmitter {
this._updatePresence = this._updatePresence.bind(this);
this._updateHealthCheck = this._updateHealthCheck.bind(this);
this.registeredRoutes = [];
this.registeredPlugins = [];

this.publisherChannels = {};
this.subscriberChannels = {};
}

/**
* @name use
* @summary Adds plugins to Hydra
* @param {...object} plugins - plugins to register
* @return {object} - Promise which will resolve when all plugins are registered
*/
use(...plugins) {
return Promise.series(plugins, plugin => this._registerPlugin(plugin));
}

/**
* @name _registerPlugin
* @summary Registers a plugin with Hydra
* @param {object} plugin - HydraPlugin to use
* @return {object} Promise or value
*/
_registerPlugin(plugin) {
this.registeredPlugins.push(plugin);
return plugin.setHydra(this);
}

/**
* @name init
* @summary Register plugins then continue initialization
* @param {object} config - configuration object containing hydra specific keys/values
* @return {object} promise - resolves with this._init
*/
init(config) {
return new Promise((resolve, reject) => {
Promise.series(this.registeredPlugins, plugin => plugin.setConfig(config))
.then((...results) => {
resolve(this._init(config));
})
.catch(err => this._logMessage('error', err.toString()));
});
}

/**
* @name _init
* @summary Initialize Hydra with config object.
* @param {object} config - configuration object containing hydra specific keys/values
* @return {object} promise - resolving if init success or rejecting otherwise
*/
init(config) {
_init(config) {
return new Promise((resolve, reject) => {
let ready = () => {
Promise.series(this.registeredPlugins, plugin => plugin.onServiceReady())
.then((...results) => {
resolve();
})
.catch(err => this._logMessage('error', err.toString()));
};
this._connectToRedis(config);
this.redisdb.select(HYDRA_REDIS_DB, (err, result) => {
if (err) {
Expand All @@ -79,11 +131,11 @@ class Hydra extends EventEmitter {
require('dns').lookup(require('os').hostname(), (err, address, fam) => {
this.config.serviceIP = address;
this._updateInstanceData();
resolve();
ready();
});
} else {
this._updateInstanceData();
resolve();
ready();
}
}
});
Expand Down Expand Up @@ -1291,6 +1343,10 @@ class IHydra extends Hydra {
return super.init(config);
}

use(...plugins) {
return super.use(...plugins);
}

/**
* @name _shutdown
* @summary Shutdown hydra safely.
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "fwsp-hydra",
"version": "0.11.5",
"version": "0.12.0",
"author": "Carlos Justiniano",
"description": "A library for building microservices - built on Redis",
"keywords": [
Expand All @@ -27,6 +27,7 @@
"fwsp-server-response": "2.2.3",
"fwsp-umf-message": "0.4.3",
"humanize-duration": "3.9.1",
"lodash": "4.17.2",
"moment": "2.15.2",
"redis": "2.6.2",
"request": "2.76.0",
Expand Down
67 changes: 67 additions & 0 deletions plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
'use strict';

const isEqual = require('lodash/isEqual');
const HydraEvent = require('./events');

/**
* @name HydraPlugin
* @description Extend this for hydra plugins
*/
class HydraPlugin {
/**
* @param {string} pluginName - unique name for the plugin
*/
constructor(pluginName) {
this.name = pluginName;
}
/**
* @name setHydra
* @param {object} hydra - hydra instance
*/
setHydra(hydra) {
this.hydra = hydra;
this.hydra.on(
HydraEvent.CONFIG_UPDATE_EVENT,
config => this.updateConfig(config)
);
}
/**
* @name setConfig
* @param {object} hydraConfig - the hydra config
*/
setConfig(hydraConfig) {
this.hydraConfig = hydraConfig;
this.opts = hydraConfig.plugins[this.name];
}
/**
* @name updateConfig
* @param {object} serviceConfig - the service-level config
* @param {object} serviceConfig.hydra - the hydra-level config
*/
updateConfig(serviceConfig) {
this.serviceConfig = serviceConfig;
this.hydraConfig = serviceConfig.hydra;
let opts = this.hydraConfig.plugins[this.name];
if (!isEqual(this.opts, opts)) {
this.configChanged(opts);
}
}
/**
* @name configChanged
* @summary Handles changes to the plugin configuration
* @param {object} opts - the new plugin config
*/
configChanged(opts) {
console.log(`[override] [${this.name}] handle changed config`);
console.dir(opts, {colors: true, depth: null});
}
/**
* @name onServiceReady
* @summary Called by Hydra when the service has initialized, but before the init Promise resolves
*/
onServiceReady() {
console.log(`[override] [${this.name}] hydra service ready`);
}
}

module.exports = HydraPlugin;
Loading

0 comments on commit fc3c561

Please sign in to comment.