node package manager

caf_pubsub

Cloud Assistants lib for a publish/subscribe bus

CAF.js (Cloud Assistant Framework)

Co-design permanent, active, stateful, reliable cloud proxies with your web app and gadgets.

See http://www.cafjs.com

This repository contains a CAF library that implements a publish/subscribe bus using, for example, a Redis backend.

There are two types of channels:

  • A private channel name is prefixed by the CA name, i.e., <ca_name>-<whatever>, and only that CA can publish messages.

  • A forum channel has a name of the form forum-<whatever>, and anybody can publish to it. However, subscribers can filter publishers using method ACLs, since pubsub messages are always processed by invoking a CA method. This method is chosen by the subscriber.

Currently, anybody can subscribe to a channel if they know its name, and we recommend to use hard to guess channel names to limit visibility.

The delivery guarantees depend on the pubsub backend service. Redis, for example, is best effort. However, when the plugin has committed to publish a message, it will retry after a CA or node.js process crash.

A pubsub service complements well a SharedMap (see {@link external:caf_sharing}). SharedMaps are silently updated, and this makes them very efficient when shared by many CAs. Messages generated by a pubsub service are processed by subscribed CAs and, for example, can trigger external actions. By combining them, we can get the right mix of silent updates vs external actions.

CAF.js discourages point-to-point communication between CAs. At the network infrastructure level, point-to-point becomes all-to-all very quickly, limiting the scalability of the system.

Similar to MPI collective calls, applications should expose higher-level communication patterns. These patterns can scale better with specialized services, such as SharedMap or pubsub.

However, if you really need point-to-point, you can always use a private pubsub channel, or write a new plugin...

The following example has a privileged CA, i.e., admin, that regularly publishes messages in a private channel. CAs with the same owner subscribe to this channel, and the handler function notifies clients using sessions (see {@link external:caf_session}).

exports.methods = {
    __ca_init__: function(cb) {
        this.state.counter = 0;
        this.$.pubsub.subscribe(masterChannel(this), 'handleMessage');
        cb(null);
    },
    __ca_pulse__: function(cb) {
        if (isAdmin(this)) {
            this.state.counter = this.state.counter + 1;
            this.$.pubsub.publish(masterChannel(this),
                                  'Counter: ' + this.state.counter);
        }
        cb(null);
    },
    handleMessage: function(topic, msg, cb) {
        this.$.log && this.$.log.debug('Got ' + msg);
        this.$.session.notify([msg]);
        cb(null);
    }
}

A couple of helper functions for naming:

var ADMIN_CA = 'admin';
var ADMIN_CHANNEL = 'myNews';
var isAdmin = function(self) {
    var name = self.__ca_getName__();
    return (json_rpc.splitName(name)[1] === ADMIN_CA);
};
var masterChannel = function(self) {
    var name = self.__ca_getName__();
    return json_rpc.joinName(json_rpc.splitName(name)[0], ADMIN_CA,
                             ADMIN_CHANNEL);
};

See the client code in examples/helloworld/client1.js

See {@link module:caf_pubsub/proxy_pubsub}

See {@link module:caf_pubsub/plug_pubsub}

See {@link module:caf_pubsub/plug_ca_pubsub}