• Meteor

Mechanics of PubSub

From the class:  Publish Subscribe in Meteor

Let's take a look at the mechanics of pub/sub by looking at code and using a server-side debugger. On the left, I have the console that I'll be using to connect to our DDP server and subscribe to the Items publication.

On the right top is my server code, where I've created a Publish function by calling Meteor Publish, giving the Publish function a name, and then a Handler function. This Handler function takes a parameter which we can pass up as part of the pub/sub protocol. And then, so far, the Handler just runs a console log so we can see that we're inside of the body.

And down below, I have Node Inspector running. And if you need a review on how to use Node Inspector and the DDP tools, you can go back to some of the intro videos where we actually installed them.

So inside of the debugger, I've set two breakpoints. And what we want to do next is to subscribe to this Publish function and take a look at what's happening.

In my client console on the left, I'll type DDP subscribe, and then, give a name of the subscription. We're going to subscribe to the Items Publish function, or the Items subscription. That should drop me over into my debugger on the server for the sub protocol Handler.

The first thing to note is we're dropped into the session object for this connected client. And the session object, if you recall from the session videos, has a bunch of protocol handlers for each of the possible DDP messages that we could get. And one of those is called Sub for the subscription message that has been sent up.

The first thing that it's going to do is to find the Handler function, which is this function here that we created when we called Meteor Publish. And that Handler function is stored on the server object. Let's take a look at it in the Watch Expression area.

In the Watch Expression area, I created a new watch for Meteor server so we can take a look at the server instance. And you can see there's a property there called Publish Handlers. And that's where Meteor puts the various Publish Handler functions. And so we have one function called Items. And that's the one that we created up here. So when each connected client, when a connected client subscribes to Items, it's going to share this Handler function.

So the next thing that happens here is Meteor calls this function called Start Subscription. And this is where it's actually going to start up the subscription by creating a new subscription object. So to see that, we can press Play in the debugger and move to the next breakpoint, which is inside of this Start Subscription function.

Now, what this will do is first create a new subscription. And you can see that code here. And the new subscription object will stick around for the entire duration of the subscription, or until the clients unsubscribe from it.

And then finally, Meteor will run the Handler, which is this function here, by calling the Run Handler method of the subscription.

I'll press Play again in the debugger. And now, we've been dropped into the Publish function itself. The first thing to note is that this, inside of this Publish function, points to the new subscription object that we just created. And that subscription object has some properties on it. And it also has some functions that you may be used to calling from your own applications, like Added, Changed, and Ready. And the idea is that from inside of this function, we can send messages to the client about this data set.

And so to play around, let's just send some messages manually. First, let's pretend that we're adding some documents. And so we're going to tell the client that there's, say, two documents that need to be added. So I'll call this dot added. And the first thing the Added function wants is the name of the collection. Now, that can be the same name as the Publish function, or it can be something different. In this case, it'll just be the same thing. So the name of the collection will be Items. And then we'll give it some ID, and then some fields to add.

There may be a little bit of a debug delay, but eventually, that will send a message down to our client on the left. Specifically, it will send an Added message.

OK. There we go. Over on the client, it received a message called Added. And you could see some extra properties were added to the message, like the collection name, the ID of the document, and then our fields.

Let's send one more Added message. We'll pretend that we have two items in this collection. So we'll send both of them. And a second message, now, was sent to the client with our second item.

Now, when we've sent all the initial documents, we need a way to tell the client that we're done. And the way we can do that is by sending a Ready message. And it's pretty simple to send a Ready message. You just have to type this dot ready. And the Ready message tells the client that the initial two documents-- or the initial data set, however many there may be-- have been sent down to the client.

Now, at some later time, maybe a couple minutes later, we might send some additional messages. So the server, or the Publish function, can continue to send these messages over time until the client decides to unsubscribe.

Let's say that one of the documents changes. To send a Changed message, we can call the Changed method of the subscription. Again, I'll provide the name of the collection, and then the ID of the document that's changing. And we'll say that the title has just change from 1 to New Title. And the corresponding DDP message is sent down to the client, telling it to change this document with an ID of 1 in the collection of Items. And here are the actual changed fields.

We might also want to remove a document from the collection. And to do that we can use the Removed method. For the Removed message, we'll pass the name of the collection, and just the ID. And that will send a DDP message to the client telling it to remove the item with ID 1 from the Items collection.

Let's update our code a little bit to send these messages here, instead of from within the debugger. So a typical Publish function might typically send some Added messages, just like we did before. And then, when the initial result set is done, we'll send the Ready message.

And then, to simulate the document changing over time, let's use the Set Interval method of JavaScript. And we'll say every two seconds, we'll send an Updated message. Now, we need to get a reference of this. So I'm going to save r self is equal to this, so that we can call inside of this function. And every two seconds, we'll call the Changed method for Items, and we'll change Document 1. And I'll just give it a random ID.

And then, over on the-- let me get rid of these debug points, because we don't need to debug this anymore. But in the left, I will connect or subscribe again to the Items publication. And we could even pass up an ID, although we're not using that right now.

So I get my initial Added messages, and then the Ready message. And then, every two seconds, I get a Changed message to change Document 1. And this is simulating what might happen if you're publishing out changes from a Mongo collection.

Next, let's look at how we can subscribe using JavaScript inside of a browser. So now on the left, instead of a console client, we're going to use the browser client. And so this is our client. And we have another browser again over here. But just to make sure it's not confusing, this is for our server-side debugging.

And what I've done inside of the client is clicked the Network tab and then the WebSockets, so that we can take a look at the WebSocket, our DDP messages that are being sent over time.

The next thing I want to do is in the console, create a subscription and subscribe to this publication up here. So to do that, let me clear this out. And I'm going to create a variable called Sub that I'll assign the result of the subscription to. And I'll show you what we can do with that in a minute. So to subscribe, I'll call Meteor Subscribe, which just proxies to the underlying connection to subscribe. And I'm going to subscribe to the Items publication. And I could pass up an ID if I want to. But again, we're not using that in this Publish function.

Now, we'll look at the DDP messages in a sec. But look at the subscription object that gets returned. It has two functions-- Stop and Ready. The Ready method tells us whether or not we've received the Ready message. In this case we have, and so it returns True. This function is reactive. And so if you're running it inside of a computation and its value changes, the computations function will be re-run. If that concept is confusing, you can go and watch the [? DEPS ?] class.

We'll talk about the Stop function in a second. This allows us to unsubscribe from this subscription.

But before we do that, let's take a look at the WebSocket. And so I've refreshed the WebSocket so we can take a look at the DDP messages that have been sent. We can see initial subscription message sent up from the client here, and then our two Added messages that get sent from this dot added and this dot added, and then the Ready message. And then after that, every two seconds, we send a Changed message to illustrate how we can change a document over time.

So this debugging technique can be really useful with subscriptions. You can use Chrome to see which DDP messages are being sent from the server and up from the client.

Next up, let's stop the subscription. Before we call the Stop function, over on the server-side debugger, I'm going to scroll down into one of the protocol handlers called Unsub. And I've set a breakpoint here so we can stop and see what's happening when that message gets sent up.

Then, over the left, I'll call sub dot stop. That'll drop us into our server-side debugger. But if I refresh the WebSockets, you can see a message has been sent up to the server. And the message is Unsub. And so Unsub gets sent up as a message to the server. And then this Protocol Handler will run. And what this will do is called the Stop Subscription function on our subscription.

And if we step forward a little bit more, you can see that inside Stop Subscription, the first thing that happens is all the documents associated with that subscription are removed. And then, the subscription is deactivated. And the object associated with the subscription we created is deleted.

When I press Play and continue, you can see a couple of messages have been sent down to the client to stop this subscription. So here's the Unsub message sent up from the client to the server. And then, the server sends two Removed messages to remove these items, Items 1 and Items 2, from the client view, because since we're no longer subscribed, then the client shouldn't see these documents anymore.

And then finally, when it's done, it sends this No Sub message, saying that the subscription is over.

So normally, inside of our Publish functions, we don't send these messages manually like this. We usually just return a cursor. But I wanted to do it manually in this case so you get a better sense of what's actually happening inside of a Publish function.

So to recap, I hope this video gave you a better sense of what happens when a client subscribes, including the DDP messages that are sent back and forth, and what we can do inside of a Subscription Handler, by calling this dot added, changed, removed, and ready.

Finally, we looked at what we can do with the object that's returned from Meteor subscribe on the client, how we can use the Ready method to see whether or not we've received the Ready message, and then, the Stop function to stop the subscription by sending up an Unsub message, and then having the server clean up whatever documents we no longer need to see.