Improving Performance with WebSockets

Development

Reading Time: 3 minutes

Nearly a year ago, we released Shipscope, a Chrome extension for monitoring your projects on Codeship. We’ve received some really good feedback from our users, and I want to share some of that insight in this post.

In order to provide frequent status updates, Shipscope requested project status from our API server every 10 seconds. Multiply this by a rapidly growing userbase, and it really amounted to something.

There were two consequences of Shipscope’s frequent polling:

  1. As Shipscope became more popular, the load on our API server grew. This was not a critical problem, but if we can reduce the number of requests to our API server while providing timely updates to users, then we should really try to do that.

  2. Shipscope stayed pretty busy in the user’s browser, frequently requesting updates which most often would report no change to any build status. This is just wasteful use of CPU.

In our web-based UI, we have been using Pusher for a while to provide build progress updates to the browser via WebSockets. Using Pusher, our web client never needs to poll the server for build progress updates. The server sends a message on the socket when progress occurs in the build. The client then requests build info from the server and updates the UI. This provides immediate updates without any unnecessary polling.

For security reasons, we don’t send full build information across the WebSocket. We don’t want to send customer build info over a connection that could be unencrypted. Pusher allows payloads to be encrypted between the server and Pusher and then from Pusher to the client over the WebSocket.

However, that transfer between the HTTP port and the WebSocket port is not encrypted. Rather than trying to encrypt the build info before we send it, we choose to limit the data that we send over the WebSocket. So, the client is notified of an update, and the full update info is fetched securely over an HTTPS connection.

New Call-to-action

This approach has worked very well for us with our web client, so we decided we should give it a try with Shipscope. The first step is to get a Pusher app key, which is easy enough once you signup at Pusher’s website.

After installing Pusher’s JavaScript client, Shipscope initializes a Pusher instance like so:

pusher = new Pusher(PUSHER_APP_KEY, {
    authEndpoint: 'https://codeship.com/pusher/auth',
    auth: {
      params: {
        api_key: options.api_key
      }
    },
    encrypted: true
})

The authEndpoint and auth properties allows us to verify that Shipscope can only subscribe to updates for which the api_key authorizes it. encrypted ensures that messages to and from Pusher are not in plain text.

Once we have a Pusher instance, we only need to subscribe to a channel. Each project has its own channel for publishing updates. So, if we are monitoring a project with id, 9876, then we’ll subscribe like this:

var channel = pusher.subscribe("private-project-9876")

and finally,

channel.bind(UPDATE_EVENT, onUpdate.bind(projectInfo))

will call onUpdate() with projectInfo bound to this every time a build starts or finishes in our project.

That saves a lot of effort for both Shipscope running in your browser and our API server, which now only gets requests when something interesting has happened.

One more thing that we get from Pusher is offline notification. If you somehow find yourself away from a wifi connection, the Pusher client fires a state_change event to let Shipscope know. We use this currently to change the Shipscope icon to red to let you know that Shipscope is offline.

Setting this up is as simple as:

pusher.connection.bind('state_change', function() {
  if (pusher.connection.state == 'connected') {
    chrome.browserAction.setIcon({path: 'img/shipscope_icon_19.png'})
    getShipscopeSummary()
  } else {
    chrome.browserAction.setIcon({path: 'img/shipscope_icon_19_error.png'})
    chrome.browserAction.setBadgeText({text: ''})
  }
})

WebSockets have made a big difference to both our server and the Shipscope Chrome extension. Pusher made WebSockets easy. You can install Shipscope from the Chrome Web Store. Shipscope is open source, so feel free to review the code at https://github.com/codeship/shipscope.

Subscribe via Email

Over 60,000 people from companies like Netflix, Apple, Spotify and O'Reilly are reading our articles.
Subscribe to receive a weekly newsletter with articles around Continuous Integration, Docker, and software development best practices.



We promise that we won't spam you. You can unsubscribe any time.

Join the Discussion

Leave us some comments on what you think about this topic or if you like to add something.