Pub/Sub

The pub/sub (publish/subscribe) function enables senders (publishers) to publish messages on "channels" and enables receivers (subscribers) to subscribe to the channels and receive messages when they are sent. The "hello world" application of pub/sub is often a chat application, but let's defy tradition and use pub/sub in an IoT scenario instead.

Is my Garage Door Open or Closed?

Garage

In our scenario, we want to be notified when our garage door is opened or when it is closed. To accomplish this, we connect a Raspberry Pi to a garage door sensor using an Arduino, Particle Photon, XBee, or some other means. We then run a Node.js application on the Raspberry Pi to publish the garage door open/close events, and we run a Node.js application on another system to receive notification when events occur.

For the sake of our demo, we will run both the publisher and subscriber on the same system, and this system will also host the Redis server.

Create Redis Subscriber

Let's get started and create a Node.js console application called subscriber.js and add the following contents:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
const Redis = require('ioredis');

const redis = new Redis();

redis.on('message', (channel, message) => {
    console.log(`Received the following message from ${channel}: ${message}`);
});

const channel = 'garageDoor';

redis.subscribe(channel, (error, count) => {
    if (error) {
        throw new Error(error);
    }
    console.log(`Subscribed to ${count} channel. Listening for updates on the ${channel} channel.`);
});

Our subscriber utilizes a handler in line 5 to receive incoming messages from the publisher.

In line 11, we subscribe to the garageDoor channel and wait to receive events. When invoked, this program will continue to run until the user halts its execution with Ctrl+C.

Create Redis Publisher

Next, we create a Node.js console application called publisher.js to publish our garage door open/close events as they occur:

const Redis = require('ioredis');

const pub = new Redis();

const channel = 'garageDoor';

const sleep = sec => new Promise(resolve => setTimeout(resolve, sec * 1000));

async function main() {
    console.log('Started garage door publisher...')
    // Sleep 4 seconds and then publish garage door "opened" event.
    await sleep(4);
    pub.publish(channel, 'opened');

    await sleep(7);
    pub.publish(channel, 'closed');
    pub.disconnect();
}

main();

We use a sleep function in line 7 to introduce delay times in the program so we can simulate gaps and publish events at varying times.

In line 13, we publish our first event on the garageDoor channel (after a 4 second delay) to let our subscriber(s) know that the garage door has opened.

In line 16, we publish our second event (7 seconds later) to indicate that the garage door has been closed.

Test the Garage Door Pub/Sub Programs

Now it's time for the moment of truth:

Open a terminal window and issue the following command:

$ node subscriber.js

Launch a second terminal window and fire up the publisher application:

$ node publisher.js

Watch the terminal hosting the subscriber application carefully and expectantly. :smiley:

You should see the following output after 4 seconds and an additional 7 seconds have elapsed:

Subscribed to 1 channel. Listening for updates on the garageDoor channel.
Received the following message from garageDoor: opened
Received the following message from garageDoor: closed

If you really want to go for the gusto, open another terminal window and start a second subscriber program. Re-run the publisher program, and you will see both subscribers receiving the published messages. How awesome is that? :sunglasses:

Should I Use Redis Pub/Sub for Real Applications?

As expected, the answer is "it depends". Pub/sub work wells in a variety of contexts. Please be aware, however, that subscribers are not guaranteed to receive messages. For example, if the subscriber is experiencing network connection issues or is not able to read the messages fast enough, the data from the publisher will be lost.

If we were uploading our garage door open/close events to a cloud historian and could afford to miss any events, we would not want to rely on Redis pub/sub to relay the events to the cloud. A better approach would be to buffer the events in a Redis list, and rely on our subscriber to empty the Redis list. During those times when the subscriber was unavailable, the events would continue to buffer in the Redis list for the subscriber to retrieve and send to the cloud at a future time.

results matching ""

    No results matching ""