File: include/system/registry/redis_registration_provider.js
- /*
- Copyright (C) 2016 PencilBlue, LLC
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- 'use strict';
-
- //dependencies
- var util = require('../../util.js');
-
- module.exports = function RedisRegistrationProviderModule(pb) {
-
- /**
- * Implements the necessary functions in order to be able to create and manage
- * a service registry for PB processes in the cluster. This provider uses Redis
- * as the storage. In addition, it leverages Redis's expiry functionality to
- * expire entries automatically if they have not been touched. In order to
- * retrieve all nodes/processes in the cluster the provider must execute
- * Redis's "keys" function which is an expensive operation. To lessen the
- * impact on production systems the provider creates and manages its own Redis
- * client and switches to DB 2 in order to minimize the number of keys that
- * need to be scanned since the rest of the PB system leverages DB 0.
- * @class RedisRegistrationProvider
- * @constructor
- */
- function RedisRegistrationProvider(){}
-
- /**
- * The Redis DB used for storage
- * @private
- * @static
- * @readonly
- * @property REGISTRY_DB
- * @type {Integer}
- */
- var REGISTRY_DB = 0;
-
- /**
- * The character used to separate the registry key prefix from the unique value
- * that identifies the process/node.
- * @private
- * @static
- * @readonly
- * @property SEP
- * @type {String}
- */
- var SEP = '-';
-
- /**
- * The Redis client used to connect to the service registry
- * @private
- * @static
- * @readonly
- * @property CLIENT
- * @type {Integer}
- */
- var CLIENT = null;
-
- /**
- * Retrieves the entire cluster status as an array of status objects. The '_id'
- * property uniquely identifies each process/node.
- * @method get
- * @param {Function} cb A callback that provides two parameters: cb(Error, Array)
- */
- RedisRegistrationProvider.prototype.get = function(cb) {
-
- var pattern = RedisRegistrationProvider.getPattern();
- CLIENT.keys(pattern, function(err, keys) {
- if (util.isError(err)) {
- cb(err);
- return;
- }
-
- CLIENT.mget(keys, function(err, statusObj) {
-
- //do data transform
- var statuses = [];
- if (util.isObject(statusObj)) {
- for (var key in statusObj) {
- try {
- var status = JSON.parse(statusObj[key]);
- status._id = status.id || key;
- statuses.push(status);
- }
- catch(e){}
- }
- }
- cb(err, statuses);
- });
- });
- };
-
- /**
- * Updates the status of a single node.
- * @method set
- * @param {String} id The unique identifier for the process/node
- * @param {Object} status The status information
- * @param {Function} cb A callback that provides two parameters: cb(Error, [RESULT])
- */
- RedisRegistrationProvider.prototype.set = function(id, status, cb) {
- if (!util.isObject(status)) {
- cb(new Error('The status parameter must be a valid object'));
- return;
- }
-
- var key = RedisRegistrationProvider.getKey(id);
- var expiry = Math.floor(pb.config.registry.update_interval / util.TIME.MILLIS_PER_SEC);
- CLIENT.setex(key, expiry, JSON.stringify(status), cb);
- };
-
- /**
- * Purges all statuses from storage.
- * @method flush
- * @param {Function} cb A callback that provides two parameters: cb(Error, [RESULT])
- */
- RedisRegistrationProvider.prototype.flush = function(cb) {
- var pattern = RedisRegistrationProvider.getPattern();
- CLIENT.keys(pattern, function(err, keys) {
- if (util.isError(err)) {
- cb(err);
- return;
- }
-
- CLIENT.del(keys, cb);
- });
- };
-
- /**
- * This function should only be called once at startup. It is responsible for
- * creating the Redis client that connects to the service registry. It also
- * ensures the proper Redis DB is selected.
- * @method init
- * @param {Function} cb A callback that takes two parameters. cb(Error, [RESULT])
- */
- RedisRegistrationProvider.prototype.init = function(cb) {
-
- CLIENT = pb.CacheFactory.createInstance();
- CLIENT.select(REGISTRY_DB, cb);
- };
-
- /**
- * Should be called during shutdown. It is responsible for removing the
- * process/node from the registry.
- * @method shutdown
- * @param {String} id The unique identifier for the node/process
- * @param {Function} cb A callback that takes two parameters: cb(Error, [RESULT])
- */
- RedisRegistrationProvider.prototype.shutdown = function(id, cb) {
- if (!id) {
- pb.log.error('RedisRegistrationProvider: A valid ID is needed in order to properly shutdown');
- cb(null, false);
- }
-
- var key = RedisRegistrationProvider.getKey(id);
- CLIENT.del(key, cb);
- };
-
- /**
- * Creates the cache key used to store the status update
- * @static
- * @method getKey
- * @param {String} id The unique identifier for the node/process
- * @return {String} The cache key to be used for storing the update
- */
- RedisRegistrationProvider.getKey = function(id) {
- return [pb.config.registry.key, id].join(SEP);
- };
-
- /**
- * Creates the glob pattern to be used to find service registry keys
- * @static
- * @method getPattern
- * @return {String} The glob patern to be used to find all status updates
- */
- RedisRegistrationProvider.getPattern = function() {
- return pb.config.registry.key + '*';
- };
-
- return RedisRegistrationProvider;
- };
-
-