PubNub FunctionsChaining Functions with publish() and fire() APIs

In the past lesson we learned how to reuse data by first saving it, then retrieving it via the Key/Value Store (KV Store).

There is a second way to share data across PubNub Functions, and it's via chaining Event Handlers with the pubnub.publish() or the pubnub.fire() API commands.

In this exercise, we'll illustrate using the PubNub publish() and fire() methods to chain Event Handlers and forward messages between PubNub Functions.

Depending on your use case, you may wish to use the KV DB, the APIs, or both.

The KV DB is great for simply providing a common DB to share data across.

However, if you wish to trigger another event handler (in the same or in another block), using publish() and fire() methods are the way to go.

Let's add some logic to our Hello World app that will simultaneously fork the newly mutated message to another channel, hello_universe.

  1. export default (request) => {
        const db = require("kvstore");
        const pubnub = require("pubnub");
    
        console.log("The message", request.message, "was published on", request.channels[0], "via", request.meta.clientip);
    
        request.message.hello = "world!"; // augment hello = world
        delete request.message.foo; // delete the foo attribute
    
        return db.get("randNum").then((randNum) => {
    
            // db.removeItem("randNum");
    
            if (!randNum) {
                randNum = Math.random();
                db.set("randNum", randNum)
                    .catch((err) => {
                        console.log("An error occured saving the random number.", err);
                    });
    
                console.log("randNum does not exist. Creating.");
            } else {
                console.log("randNum already exists:", randNum);
            }
    
            request.message.randNum = randNum;
    
            pubnub.publish({
                "channel": "hello_universe",
                "message": request.message
            }).then((publishResponse) => {
                console.log(`Publish Status: ${publishResponse[0]}:${publishResponse[1]} with TT ${publishResponse[2]}`);
            });
    
            return request.ok();
    	});
    };
    
    
    
  2. Click Save.
  3. Click Stop Module.
  4. Click Start Module.
  5. Open a debug console tab on your browser to http://www.pubnub.com/docs/console
  6. Enter hello_world, hello_universe for the channel in the debug console.
  7. Click Subscribe.
  8. From the PubNub Functions GUI console, click Publish.

You should see that in the debug console set to hello_world, your message now appears on two channels: hello_world, and also hello_universe!

Publish Output
 

Use publish() to fork when:

  • You want to forward the data to another arbitrary channel where awaiting subscribers are listening for it. (In this case, hello_universe.)
  • You also want to make this forked message available as a trigger for another Function.
 
Additional billing fees may apply when using publish() instead of fire(), so be sure you are using publish() only when necessary.

Let's quickly step through the changed code to see what's happening.

First, we assemble a new publish configuration object, which contains two attributes:

  • The channel attribute, which designates the destination channel.
  • The message attribute, which contains the JSON message we'll be publishing.
{
    "channel": "hello_universe",
    "message":
}
pubnub.publish(forwardingMessage).then((publishResponse) => {
	console.log(`Publish Status: ${publishResponse[0]}:${publishResponse[1]} with TT ${publishResponse[2]}`);
})
 
You can chain / fork publishes across as many channels as you wish, however it's important not to create a scenario where an infinite loop is possible (for example, publishing to A, which publishes to B, which Publishes back to A.) The system is designed to detect and not allow infinite loops to happen, however, it's important to take care that your logic also doesn't encourage or rely on this behavior.

This was a great exercise in forking, but now, lets see how it can also simultaneously be used to chain to another Function.

As a simple example, let's demonstrate how we could chain messages from the Hello World Function to a new Function called Logger.

  1. Click the + symbol next to the Hello World tab to create a new Function.

    Add New EH tab

    The Create a New Event Handler dialog appears.

    Create New Event Handler
  2. For Function name, enter Logger.
  3. For Channel name, enter hello_universe.
  4. For Select an event, select Before Publish.
  5. Click Create.

    The newly created Logger Function editor comes into focus.

    export default (request) => {
        console.log(request) // show what we have inside
        return request.ok()  // done
    };
  6. export default (request) => {
        const pubnub = require("pubnub");
    
        pubnub.publish({
            "channel": "hello_logger",
            "message":request.message
        }).then((publishResponse) => {
            console.log(`Publish Status: ${publishResponse[0]}:${publishResponse[1]} with TT ${publishResponse[2]}`);
        });
    
        return request.ok(); // Return a promise when you're done
    };

    Everything in this new Function should be familiar. The message arrives, we log to the console, and then we fork it to another new channel, called hello_logger.

    Let's now watch a fork and chain in action!

  7. From the Logger Function, click Save.
  8. Click Start Module.

  9. Open a debug console tab on your browser to http://www.pubnub.com/docs/console
  10. Enter hello_world, hello_universe, hello_logger for the channel in the debug console.
  11. Click Subscribe.
  12. In the PubNub Functions GUI, change to the Mutate Message Function.
  13. Click Publish.

Observing the consequences of using publish():

Message Chain
 
 
In the below narrative, awaiting subscribers are represented by the PubNub Dev Console.
  • The message was published to hello_world via a client (in this case, the PubNub Functions GUI debug console publisher).
  • The Mutate Message Function (bound to hello_world) mutated the message in-flight, then passed it through to awaiting subscribers on the hello_world channel.
  • The Mutate Message Function (bound to hello_world) also simultaneously forked it via the publish() call to awaiting subscribers on the hello_universe channel.
  • The Logger Function (bound to hello_universe) logged the message, then passed it through to awaiting subscribers on the hello_logger channel.
  • The Logger Function (bound to hello_universe) also simultaneously forked it (via publish) to awaiting subscribers on the hello_logger channel.

Using publish(), the message will not only be forwarded internally to other event handlers bound to that destination channel, but also to awaiting subscribers listening on that channel.

The pubnub module also exposes the fire() method for chaining and forking.

Use fire() to chain and fork when:

  1. You DO NOT want to forward the data to another arbitrary channel where awaiting subscribers are listening for it.
  2. You ONLY want to make this forked message available as a trigger for another Function.

Let's modify the example we just did for publish() to demonstrate the difference in fire() functionality.

  1. In the PubNub Functions GUI, change to the Mutate Message Function EH.
  2. pubnub.publish

    with

    pubnub.fire
  3. Click Save.
  4. Click Restart Module.
  5. Open a debug console tab on your browser to http://www.pubnub.com/docs/console
  6. Enter hello_world, hello_universe, hello_logger for the channel in the debug console.
  7. Click Subscribe.
  8. In the PubNub Functions GUI, change to the Mutate Message Function.
  9. Click Publish.

Observing the consequences of using fire() (instead of publish):

Observing consequences of using fire instead of publish
 
 
In the below narrative, awaiting subscribers are represented by the PubNub Dev Console.
  • The message was published to hello_world via a client (in this case, the PubNub Functions GUI debug console publisher).
  • The Mutate Message Function (bound to hello_world) mutated the message in-flight, then passed it through to awaiting subscribers on the hello_world channel.
  • The Mutate Message Function (bound to hello_world) also simultaneously forked it via the fire() call. Because it's fire() and not publish(), it will not be delivered to awaiting subscribers on the hello_universe channel. However, it will trigger any Function(s) listening on the hello_universe channel.
  • The Logger EH (bound to hello_universe) logged the message, then passed it through to awaiting subscribers on the hello_logger channel.
  • The Logger EH (bound to hello_universe) also simultaneously forked (via publish) it to awaiting subscribers on the hello_logger channel.

Using fire(), the message will only be forwarded internally to other event handlers, and not awaiting subscribers listening on that channel.

 
PubNub Functions provides a rich set of tools, and this documentation does not cover all of the potential situations you may encounter. If you need help with a situation not covered by the documentation, please contact PubNub Support.