API Docs for: 0.8.0
Show:

File: include/system/registry/redis_registration_provider.js

  1. /*
  2. Copyright (C) 2016 PencilBlue, LLC
  3.  
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13.  
  14. You should have received a copy of the GNU General Public License
  15. along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. 'use strict';
  18.  
  19. //dependencies
  20. var util = require('../../util.js');
  21.  
  22. module.exports = function RedisRegistrationProviderModule(pb) {
  23.  
  24. /**
  25. * Implements the necessary functions in order to be able to create and manage
  26. * a service registry for PB processes in the cluster. This provider uses Redis
  27. * as the storage. In addition, it leverages Redis's expiry functionality to
  28. * expire entries automatically if they have not been touched. In order to
  29. * retrieve all nodes/processes in the cluster the provider must execute
  30. * Redis's "keys" function which is an expensive operation. To lessen the
  31. * impact on production systems the provider creates and manages its own Redis
  32. * client and switches to DB 2 in order to minimize the number of keys that
  33. * need to be scanned since the rest of the PB system leverages DB 0.
  34. * @class RedisRegistrationProvider
  35. * @constructor
  36. */
  37. function RedisRegistrationProvider(){}
  38.  
  39. /**
  40. * The Redis DB used for storage
  41. * @private
  42. * @static
  43. * @readonly
  44. * @property REGISTRY_DB
  45. * @type {Integer}
  46. */
  47. var REGISTRY_DB = 0;
  48.  
  49. /**
  50. * The character used to separate the registry key prefix from the unique value
  51. * that identifies the process/node.
  52. * @private
  53. * @static
  54. * @readonly
  55. * @property SEP
  56. * @type {String}
  57. */
  58. var SEP = '-';
  59.  
  60. /**
  61. * The Redis client used to connect to the service registry
  62. * @private
  63. * @static
  64. * @readonly
  65. * @property CLIENT
  66. * @type {Integer}
  67. */
  68. var CLIENT = null;
  69.  
  70. /**
  71. * Retrieves the entire cluster status as an array of status objects. The '_id'
  72. * property uniquely identifies each process/node.
  73. * @method get
  74. * @param {Function} cb A callback that provides two parameters: cb(Error, Array)
  75. */
  76. RedisRegistrationProvider.prototype.get = function(cb) {
  77.  
  78. var pattern = RedisRegistrationProvider.getPattern();
  79. CLIENT.keys(pattern, function(err, keys) {
  80. if (util.isError(err)) {
  81. cb(err);
  82. return;
  83. }
  84.  
  85. CLIENT.mget(keys, function(err, statusObj) {
  86.  
  87. //do data transform
  88. var statuses = [];
  89. if (util.isObject(statusObj)) {
  90. for (var key in statusObj) {
  91. try {
  92. var status = JSON.parse(statusObj[key]);
  93. status._id = status.id || key;
  94. statuses.push(status);
  95. }
  96. catch(e){}
  97. }
  98. }
  99. cb(err, statuses);
  100. });
  101. });
  102. };
  103.  
  104. /**
  105. * Updates the status of a single node.
  106. * @method set
  107. * @param {String} id The unique identifier for the process/node
  108. * @param {Object} status The status information
  109. * @param {Function} cb A callback that provides two parameters: cb(Error, [RESULT])
  110. */
  111. RedisRegistrationProvider.prototype.set = function(id, status, cb) {
  112. if (!util.isObject(status)) {
  113. cb(new Error('The status parameter must be a valid object'));
  114. return;
  115. }
  116.  
  117. var key = RedisRegistrationProvider.getKey(id);
  118. var expiry = Math.floor(pb.config.registry.update_interval / util.TIME.MILLIS_PER_SEC);
  119. CLIENT.setex(key, expiry, JSON.stringify(status), cb);
  120. };
  121.  
  122. /**
  123. * Purges all statuses from storage.
  124. * @method flush
  125. * @param {Function} cb A callback that provides two parameters: cb(Error, [RESULT])
  126. */
  127. RedisRegistrationProvider.prototype.flush = function(cb) {
  128. var pattern = RedisRegistrationProvider.getPattern();
  129. CLIENT.keys(pattern, function(err, keys) {
  130. if (util.isError(err)) {
  131. cb(err);
  132. return;
  133. }
  134.  
  135. CLIENT.del(keys, cb);
  136. });
  137. };
  138.  
  139. /**
  140. * This function should only be called once at startup. It is responsible for
  141. * creating the Redis client that connects to the service registry. It also
  142. * ensures the proper Redis DB is selected.
  143. * @method init
  144. * @param {Function} cb A callback that takes two parameters. cb(Error, [RESULT])
  145. */
  146. RedisRegistrationProvider.prototype.init = function(cb) {
  147.  
  148. CLIENT = pb.CacheFactory.createInstance();
  149. CLIENT.select(REGISTRY_DB, cb);
  150. };
  151.  
  152. /**
  153. * Should be called during shutdown. It is responsible for removing the
  154. * process/node from the registry.
  155. * @method shutdown
  156. * @param {String} id The unique identifier for the node/process
  157. * @param {Function} cb A callback that takes two parameters: cb(Error, [RESULT])
  158. */
  159. RedisRegistrationProvider.prototype.shutdown = function(id, cb) {
  160. if (!id) {
  161. pb.log.error('RedisRegistrationProvider: A valid ID is needed in order to properly shutdown');
  162. cb(null, false);
  163. }
  164.  
  165. var key = RedisRegistrationProvider.getKey(id);
  166. CLIENT.del(key, cb);
  167. };
  168.  
  169. /**
  170. * Creates the cache key used to store the status update
  171. * @static
  172. * @method getKey
  173. * @param {String} id The unique identifier for the node/process
  174. * @return {String} The cache key to be used for storing the update
  175. */
  176. RedisRegistrationProvider.getKey = function(id) {
  177. return [pb.config.registry.key, id].join(SEP);
  178. };
  179.  
  180. /**
  181. * Creates the glob pattern to be used to find service registry keys
  182. * @static
  183. * @method getPattern
  184. * @return {String} The glob patern to be used to find all status updates
  185. */
  186. RedisRegistrationProvider.getPattern = function() {
  187. return pb.config.registry.key + '*';
  188. };
  189.  
  190. return RedisRegistrationProvider;
  191. };
  192.