Real Time Messaging with Pusher
Every application has its dark corner. Some part of the application of which you are not proud of. That part of the application is working code, it's in production for some time but you still have an uneasy feeling about it. You fear that it will come back at you at the worst possible time.
At Codeship one of these parts was our Dashboard reload. In this article I will show you how we made it awesome.
The Codeship Project Dashboard
When you are on your dashboard, or watching the builds of a particular project or observe a certain build.
We are updating the page without you having to hit reload all the time. Every time a new build starts or we receive some new output from your test commands we update the page and you can see the changes instantly.
Back to the past
Realtime Updates with Pusher
Over the time we optimized this feature step by step. We added some checks which allowed us the respond with a 304 (Content not modified) for not having to render the page again and again even when there are no updates. The next step was to let the client save the last time it got updates from the server and included that information in the next request. This allowed us to just deliver the missing parts. We were still having that 10 second page reload. We decided to change that!
The web changed dramatically in recent years. Web sockets have been around for quite some time now and a huge ecosystem evolved around these new technologies. We never had the intention to implement our own realtime push infrastructure, thats totally out of focus. We needed somebody who handles and provides a reliable push infrastructure for us. In the back of my head i knew about PusherApp, checking their site in the past but never having a good use case to actually use Pusher.
37 changed files with 315 additions and 159 deletions.
Implementing Pusher was quite easy and really fun. Let's go into the details.
#!ruby def auth if pusher_access.can_access? params[:channel_name] response = Pusher[params[:channel_name]].authenticate(params[:socket_id]) render json: response else render text: "Not authorized", status: 403 end end
If you go to the Codeship Dashboard you can see multiple projects. If you have just 1 project you see builds from that project. If you have multiple projects you see the last 10 builds for these projects. In this case we subscribe to multiple channels. For example if I go to the dashboard I'm subscribed to the channels "private-project-7978" and "private-project-211". If there is a new build starting for one of those projects we send a message to that channel and everybody who watches that project in their dashboard gets the update.
On a normal day we push 1.3 Million messages and have 300 concurrently connected clients.
Right now we don't include the updated parts into the message we send over Pusher. This means the client still does the page reload and gets the updates from the server. If we deliver the updates straight to the client we save a lot of requests which are not needed because we have the data that changed already in our hands at the time the push gets triggered.
What we think
We are very happy with the changes we made and Pusher itself. It made the application logic a lot simpler. We don't check for not modified content anymore, since we only trigger reloads after changes happened. The next step is to push the modified content directly to all connected clients. I'm looking forward to the next improvements we gonna ship.
Let us know your experiences with Pusher. How do YOU achieve Realtime Messaging for your app?
Improve your dark corners today!
Stay up to date
We'll never share your email address and you can opt out at any time, we promise.