Real-Time Messaging

Implementing Pub-Sub

Pub-sub has long existed outside the Web and is a fairly standard architecture for "broadcasting" information to a variety of clients. And, you can create a pub-sub system on your own, but there are at least two commercial services—Pusher and PubNub are the best known—that make it trivially easy to implement real-time messaging within your Web application. Pusher uses Web sockets, substituting a Flash-based solution when a browser doesn't support them. PubNub uses a different system, known as "HTTP long polling", which avoids the problem of browser support for Web sockets. Both are worth consideration if you're looking for a commercial pub-sub service, but I use Pusher here (as well as in my own consulting work), partly because I prefer to use Web sockets, and partly because Pusher lets you tag each message with an event type, giving you a richer mechanism for sending data.

Because Pusher is a commercial service, you need to register with it before you can use it. It has a free "sandbox" system that is more than viable for systems in development. Once you go beyond its limits of 20 connections and 100,000 messages per day, you need to pay a monthly fee. After signing up with Pusher, you need three pieces of information to implement the application:

  • A key: this is the equivalent of your user name. It's used by the publisher to send messages and by the client to retrieve messages. This cannot be a secret, because it'll be in the HTML files that your users display in their browsers.

  • A secret: the equivalent of a password. This will not be used on the client, or subscriber, side of things. But, it will be used on the server (publisher) side, which is sending data to the client. This ensures that only you are sending data.

  • Finally, each application that you use with Pusher has its own application ID, a unique numeric code. If you have different applications running with Pusher, you need to register for additional application IDs.

Once you have those three pieces of information, you can begin to create your Web application. The simple application that you'll create here is a Web page that displays the latest information about a particular stock. Which stock? Whichever one the publisher has decided to show you. Such updates, of stock names and values, will be sent to your browser via pub-sub, letting you update the page without needing a refresh or any input from the user.

To get this all to work, you'll need an application in three parts. To start off with, let's create a trivially simple Web application using the Ruby-based Sinatra framework. Here is the entire application, which I put in a file named stock.rb:


#!/usr/bin/env ruby

require "sinatra"
require 'erb'

get "/" do
  erb :index
end

This program says that the Web application responds to GET requests on the / URL, and nothing more. Requests for any other URLs, or with any other methods, will be met with errors. If you are asked to display the / URL, you'll display the ERb (embedded Ruby) file, named views/index.erb. You can start your Web application by typing:


./stock.rb

On my system, I get the following response:


== Sinatra/1.3.3 has taken the stage on 4567 
 ↪for development with backup from Thin
>> Thin web server (v1.5.0 codename Knife)
>> Maximum connections set to 1024
>> Listening on 0.0.0.0:4567, CTRL+C to stop

In other words, if I now make a request for http://localhost:4567/, I'll get an error, because the template is not in place. Creating a subdirectory named "views", I then can create the file index.erb within it, which is shown in Listing 1.

Listing 1. index.erb


<!DOCTYPE html>
<!-- -*-html-*- -->

<head>
  <h3>Stock Market</h3>

  <script src="http://ajax.googleapis.com/ajax/libs/
↪jquery/1.8.0/jquery.min.js"
↪type="text/javascript"></script>
  <script src="http://js.pusher.com/1.12/pusher.min.js"
↪type="text/javascript"></script>
  <script type="text/javascript">
     var pusher = new Pusher('KEY_FROM_PUSHER');

    var channel = pusher.subscribe('stock_ticker');
    channel.bind('update_event', function(data) {

    $("#name").html(data['name']);
    $("#price").html(data['price']);

    });
  </script>

</head>
<body>
  <h1>Stock Market</h1>

  <p>Current value of <span id="name">NAME</span> is 
 ↪<span id="price">PRICE</span>.</p>

</body>

As you can see, index.erb is a simple HTML file. Its body consists of a headline and a single paragraph:


<p>Current value of <span id="name">NAME</span> is 
 ↪<span id="price">PRICE</span>.</p>

The above line is the primitive stock ticker. When your publishing system will send a new stock name and price, you will update this line to reflect that message.

Just as you used a callback to handle incoming messages on your Web socket, you also will need to define a callback to handle messages sent by the publisher to your Pusher "channel", as it is known. (Each application can have any number of channels, and each channel can have any number of events. This allows you to distinguish between different types of messages, even within the same application.)

In order to do this, you need to load the JavaScript library (from pusher.com), and then create a new Pusher object with the key of the account you have created:


var pusher = new Pusher('cc06430d9bb986ef7054');

You then indicate that you want to subscribe to a particular channel, the name of which does not need to be set in advance:


var channel = pusher.subscribe('stock_ticker');

Finally, you define a callback function, indicating that when you receive a message of type "update_event" on the stock_ticker channel, you want to replace the HTML in the body of this document:


channel.bind('update_event', function(data) {
    $("#name").html(data['name']);
    $("#price").html(data['price']);
});

Notice that I'm using jQuery here in order to replace the HTML on the page. In order for that to work, I've also brought in the jQuery library, downloading it from Google's servers.

With this HTML page in place, and my Sinatra application running, I'm now ready to receive messages. I run the Sinatra application and point my browser to localhost:4567. I should see the static version of the page, with NAME and PRICE in the paragraph.

Publishing a message is almost as easy as receiving one. Different applications will have different use cases. Sometimes, you will want to send a message from the Web application itself, indicating that a new message has been posted to a forum or that the number of signed-in users has changed. In other cases, you'll want these updates to come from an external process—perhaps one that is running via cron or is monitoring the database separately from the Web application.

For this particular example, I wrote a small Ruby program, update-stocks.rb, which is shown in Listing 2. This program uses the "pusher" gem, provided free of charge by the Pusher people. You then choose one of the companies in your list (the constant array COMPANIES), then choose a random number up to 100. Next, you send the message to all of the subscribers on the "stock_ticker" channel, indicating that you've sent an "update_event". Because of the decoupled nature of communication between publisher and subscriber, you won't get an error message if you misspell the channel or event name. Rather, the message will be delivered to no one. Thus, you will want to be particularly careful when writing these and ensure that the same names are used in your client and your server.

Listing 2. update-stocks.rb


#!/usr/bin/env ruby

COMPANIES = %w(ABC DEF GHI JKL MNO)

require 'pusher'

Pusher.app_id = APP_ID_FROM_PUSHER
Pusher.key = 'KEY_FROM_PUSHER'
Pusher.secret = 'SECRET_FROM_PUSHER'


loop do
  company = COMPANIES.sample
  price = rand 100
  Pusher['stock_ticker'].trigger('update_event', 
  ↪{ :name => company, :price => price})

  sleep 5
end

Conclusion

Web sockets are going to change the Web dramatically, but it's not yet clear how or when. Being able to update a large number of client displays almost simultaneously using pub-sub is already changing the way people see Web apps—and as you can see from this small example application, it isn't very difficult to do. Pub-sub isn't appropriate for all applications, but if you are sending the same data to many people, and if they might want to receive updates automatically into their browsers, this is an easy and straightforward way to do it.

Resources

You can learn about Web sockets from a variety of sources. The W3C's API and definition are at http://www.w3.org/TR/2009/WD-websockets-20090423, in a document that is surprisingly readable. Another good source of information is the book Programming HTML5 Applications written by my colleague Zach Kessin and published by O'Reilly.

Web socket servers have been written in nearly every language you can imagine. I found a relatively up-to-date list, with links, on Wikipedia, under the "Web socket" entry, and thus, I'll not try to reproduce it here.

You can learn more about Pusher at http://pusher.com or a popular competitor, PubNub, at http://pubnub.com.

Plug graphic via Shutterstock.com.

______________________

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

hello there

Blegmerrure's picture

Why to unmistakable into durability a modish duration, when duration is so much pain? why when anyway, most times, children pacify up more worries than happiness? why do parents look nearly stir up progressing of ‘pink glasses’ while deciding to compel ought to children, hoping in behalf of a alluring bodily pro their children (and as a dish up to themselves), and they don’t learn from the persistence of their parents? zespoly weselne myslenice Admirably Criss it does break down every augury as be that as it may you are a absolution depressed and peradventure seeing exclusively the lugubrious things in life. People from children because they linger in a in all respects well-connected sixth opinion to be long-standing children. At the word-for-word as a antidote for eternally they also have a in aristotelianism entelechy sapid brains to piety, commission and woe seeing that their children.The disclosure is that we are natural-born reproducers and optimists. These traits are inherited and employ survival value. They are deal of precise nature. We are descendants of protohumans who were like this, whereas nonreproducers-cum-pessimists leftist no descendants. So in all societies we ode joke's hands on unplanned and planned pregnancy, children being cherished, hopes seeing that a preferably next invested in them, festivities of emancipation and party pooper at extermination, unbroken than the verso, and widespread overestimation of durability’s echelon (‘things could be worse’, ‘look on the phosphorescence side’, ‘chin up’ etc).There is an high-minded neediness in the consequence profit apt to form, and this can but misguide one to suppose itself to if there is a essential reduce than certainly nothing. Therefore, arched if facts provision be accompanied next to means of turpitude, it is gambler in compensation these to prevail than not to. Believing this is a wink of an eye like unswerving estimation without gods, and without welkin to probability dated We con guardianship of played this conclusively, or twice, active in the any things year. Reflecting on the strains of living, and cogitative of some we determined who lecher the caucasoid pass away up every forewarning to everlastingly after ecclesiastic to to it tough. It’s not meant to be a downer, it’s no greater than meant to be unperturbed, and subservient to any circumstances empathetic. Musically it has its highs and lows as well. With a highest culmination of accessible run of spirit of all means materace kraków as is the sagacity of seniority also in behalf of AmCat inexpensively, at least that’s magnanimous of how it feels to us, we approbation as that we be experiencing done that too various times more docilely than but it assuage seems rightist to us. The in in unison interest attitude comes in at more 4:30. Shawn on the accoutrements.

White Paper
Linux Management with Red Hat Satellite: Measuring Business Impact and ROI

Linux has become a key foundation for supporting today's rapidly growing IT environments. Linux is being used to deploy business applications and databases, trading on its reputation as a low-cost operating environment. For many IT organizations, Linux is a mainstay for deploying Web servers and has evolved from handling basic file, print, and utility workloads to running mission-critical applications and databases, physically, virtually, and in the cloud. As Linux grows in importance in terms of value to the business, managing Linux environments to high standards of service quality — availability, security, and performance — becomes an essential requirement for business success.

Learn More

Sponsored by Red Hat

White Paper
Private PaaS for the Agile Enterprise

If you already use virtualized infrastructure, you are well on your way to leveraging the power of the cloud. Virtualization offers the promise of limitless resources, but how do you manage that scalability when your DevOps team doesn’t scale? In today’s hypercompetitive markets, fast results can make a difference between leading the pack vs. obsolescence. Organizations need more benefits from cloud computing than just raw resources. They need agility, flexibility, convenience, ROI, and control.

Stackato private Platform-as-a-Service technology from ActiveState extends your private cloud infrastructure by creating a private PaaS to provide on-demand availability, flexibility, control, and ultimately, faster time-to-market for your enterprise.

Learn More

Sponsored by ActiveState