Eventing and PubSub


Best practices and techniques


@eschoff - @funkytek - @uhduh - @wearefractal

Consulting, training, products, professional services

contact@wearefractal.com

Open source is at github.com/wearefractal







Quick Dive


PubSub

Subscribers/Publishers can be components of the same system or pieces of entirely different systems


PubSub is fundamentally an async control flow pattern


PubSub is a core piece of many people's "secret scale sauce"


Components need no knowledge of other components, just of the main bus


PubSub is used heavily in Javascript


Publishing is usually fire and forget. Publishers almost never care who is listening.

Browser


addEventListener(event, fn) for listening to DOM events


var el = document.getElementById("usernameField");
el.addEventListener("submit", checkValue, false);

EventEmitter


ee.on(event, fn) for listening to events

ee.emit(event, args...) for emitting to events


var user = new User({name: "Mark"});
user.on('saved', function(){
  console.log("User", this.name, "saved to the db!");
});

user.emit('saved');

EventEmitters are fire and forget. You don't know or care who is listening.

Redis Sub


Connect to a channel and listen for events


var redis = require("redis");
var client = redis.createClient();

// set up message handler
client.on("message", function(channel, data){
  console.log("Received", data, "from channel", channel);
});

client.subscribe("a nice channel");

Redis Pub


Connect to a channel and publish for events


var redis = require("redis");
var client = redis.createClient();

client.publish("a nice channel", "some stuff happened!");

Redis channels are fire and forget. You don't know or care who is listening.

WebSockets


Open a bidirectional channel and send events back and forth


var WebSocket = require('ws');
var ws = new WebSocket('ws://example.com/test');

ws.on('message', function (data) {
  console.log("Received", data);
});

ws.send('test');

Flight (Web Framework)







Let's use it


Workshop


git clone https://github.com/wearefractal/eventing-pubsub-workshop
cd eventing-pubsub-workshop
npm install

Problem 1


var redis = require("redis");
var client = redis.createClient();

// publish a Hello World! to test-channel
// Use client.publish

Problem 1 Solution


var redis = require("redis");
var client = redis.createClient();

// publish a Hello World! to test-channel
// Use client.publish
client.publish("test-channel", "Hello World!");

Problem 2


var redis = require("redis");

var client = redis.createClient();
var subclient = redis.createClient();

// a JSON object is being published to test-channel
var sendMessage = function(){
  var obj = {
    test: "Hello World!"
  };

  client.publish("test-channel", JSON.stringify(obj));
};

setTimeout(sendMessage, 2000);

// subscribe to the channel using subclient.subscribe
// since all redis messages need to be strings
// you will need to parse the object
// log the parsed message

Problem 2 Solution


var redis = require("redis");

var client = redis.createClient();
var subclient = redis.createClient();

// a JSON object is being published to test-channel
var sendMessage = function(){
  var obj = {
    test: "Hello World!"
  };

  client.publish("test-channel", JSON.stringify(obj));
};

setTimeout(sendMessage, 2000);

// subscribe to the channel using subclient.subscribe
// since all redis messages need to be strings
// you will need to parse the object
// log the parsed message

subclient.on("message", function(channel, msg) {
  var parsed = JSON.parse(msg);
  console.log(parsed);
});

subclient.subscribe("test-channel");

Problem 3


var WebSocket = require('ws');
var server = require('./setup'); // load server

var port = process.env.PORT || 9080;
var socket = new WebSocket('ws://localhost:'+port+'/test');

// in this scenario we are the browser
// we have an open websocket connection to a socket server
// on 'open', send it 'Hello!' and log what it sends back

Problem 3 Solution


var WebSocket = require('ws');
var server = require('./setup'); // load server

var port = process.env.PORT || 9080;
var socket = new WebSocket('ws://localhost:'+port+'/test');

// in this scenario we are the browser
// we have an open websocket connection to a socket server
// on 'open', send it 'Hello!' and log what it sends back
socket.on('open', function(){
  socket.send('Hello!');
});

socket.on("message", function(data){
  console.log(data);
});

Problem 4


var WebSocketServer = require('ws').Server;
var wss = new WebSocketServer({port: process.env.PORT || 9080});
var client = require('./setup');

wss.on('connection', function(socket) {
  // in this scenario we are the server
  // when a socket connects set up a listener for the
  // message event on the socket that
  // logs the message and replies "Whats up!"
});

Problem 4 Solution


var WebSocketServer = require('ws').Server;
var wss = new WebSocketServer({port: process.env.PORT || 9080});
var client = require('./setup');

wss.on('connection', function(socket) {
  socket.on("message", function(msg){
    console.log(msg);
    socket.send("Whats up!");
  });
});






Questions?


Eventing and PubSub in Node

By Eric Schoffstall

Eventing and PubSub in Node

Eventing, Redis, PubSub, musings, etc.

  • 8,184