API Docs for: 0.8.0
Show:

File: include/system/registry/mongo_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 MongoRegistrationProviderModule(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 MongoDB
     * as the storage.  In addition, it leverages MongoDB's TTL collections.  The
     * reaper for mongo runs every 60 seconds.  It is possible for dead processes to
     * appear in the status list for up to that magical 60 second threshold.  The
     * name of the collection used to store all statuses is determined by the
     * configuration property: "registry.key".
     * @class MongoRegistrationProvider
     * @constructor
     */
    function MongoRegistrationProvider(){}

    /**
     * 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)
     */
    MongoRegistrationProvider.prototype.get = function(cb) {

        var dao = new pb.DAO();
        dao.q(pb.config.registry.key, {where: pb.DAO.ANYWHERE}, cb);
    };

    /**
     * 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])
     */
    MongoRegistrationProvider.prototype.set = function(id, status, cb) {
        if (!util.isObject(status)) {
            cb(new Error('The status parameter must be a valid object'));
            return;
        }

        status[pb.DAO.getIdField()] = id;
        status.object_type = pb.config.registry.key;
        var dao = new pb.DAO();
        dao.save(status, cb);
    };

    /**
     * Purges all statuses from storage.
     * @method flush
     * @param {Function} cb A callback that provides two parameters: cb(Error, [RESULT])
     */
    MongoRegistrationProvider.prototype.flush = function(cb) {
        var dao = new pb.DAO();
        dao.delete(pb.DAO.ANYWHERE, pb.config.registry.key, cb);
    };

    /**
     * This function should only be called once at startup.  It is responsible for
     * setting up the collection and ensuring that the TTL index is configured
     * correctly based on the the executing processes configuration.  <b>NOTE:</b>
     * The collection only supports one TTL value. The last process to startup and
     * configure the index will win.  Please be careful to ensure that all PB
     * processes/nodes have the same registry.update_interval value.
     * @method init
     * @param {Function} cb A callback that takes two parameters. cb(Error, [RESULT])
     */
    MongoRegistrationProvider.prototype.init = function(cb) {

        //prepare index values
        var expiry    = Math.floor(pb.config.registry.update_interval / util.TIME.MILLIS_PER_SEC);
        var procedure = {
            collection: pb.config.registry.key,
            spec: { last_modified: 1 },
            options: { expireAfterSeconds: expiry }
        };

        //ensure an index exists.  According to the MongoDB documentation ensure
        //index cannot modify a TTL value once it is created.  Therefore, we have
        //to ensure that the index exists and then verify that the expiry matches.
        //When it doesn't match we must create a system lock, drop the index, and
        //recreate it.  Due to the permissions levels of some mongo hosting
        //providers the collMod command cannot be used.
        var TTLIndexHelper = require('../../dao/mongo/ttl_index_helper.js')(pb);
        var helper = new TTLIndexHelper();
        helper.ensureIndex(procedure, cb);
    };

    /**
     * Should be called during shutdown.  It is responsible for removing the
     * process/node from the registry.
     * @static
     * @method shutdown
     * @param {String} id The unique identifier for the node/process
     * @param {Function} cb A callback that takes two parameters: cb(Error, [RESULT])
     */
    MongoRegistrationProvider.prototype.shutdown = function(id, cb) {
        pb.log.debug('MongoRegistrationProvider: Shutting down...');

        //verify an ID was passed
        if (!id) {
            pb.log.error('MongoRegistrationProvider: A valid ID is needed in order to properly shutdown');
            cb(null, false);
        }

        //ID is always a string so we don't use pb.DAO.getIdWhere(id)
        var where = {};
        where[pb.DAO.getIdField()] = id;
        var dao = new pb.DAO();
        dao.delete(where, pb.config.registry.key, cb);
    };

    return MongoRegistrationProvider;
};