Showing posts with label redis. Show all posts
Showing posts with label redis. Show all posts

Saturday, April 20, 2013

Using Sidekiq with Faye to notify client web pages and applications of updates

Recently I was given a small coding challenge of how I would update sites & client applicaitons with notifications of content being released. My mind immediately flew to the faye gem. However, this would be a serious block if my app had to halt everything to send out the notification to a bunch of browsers. So, I added in Sidekiq. In the Content Model I put this to call out to Sidekiq:
  def self.release_next
    ContentWorker.perform_async
  end
The ContentWorker then looks like this:
class ContentWorker
  include Sidekiq::Worker
  sidekiq_options queue: "content"

  def perform
    next_release = Content.next_release(Content.last_release)
    # puts the data into JSON format; for actual content it could encode a url that is then loaded
    vars = ["title" => next_release.title,
             "site" => next_release.site,
             "released_at" => next_release.released_at.strftime("%l:%M:%S %p %m-%d-%Y")].to_json
    message = {:channel => "/releases", :data => vars, :ext => {:auth_token => FAYE_TOKEN}}

    uri = URI.parse(FAYE_SUBSCRIPTION_PATH)
    Net::HTTP.post_form(uri, :message => message.to_json)
    next_release.update_attribute(:released_at, DateTime.now)
  end
end
I created a designated queue in Sidekiq for the messages and then made the Faye channel creation configurable via an environment variable from an initializer file (/config/initializers/faye_configuration.rb):
FAYE_SUBSCRIPTION_PATH = "http://localhost:9292/faye"
The client then just listens in on the Faye channel and acts upon a message coming through. Here is the Javascript I wrote for listening to the Channel and adding the new release to the top of the view table just below the headers:
$(function() {
   var faye = new Faye.Client("http://192.168.0.12:9292/faye");
   faye.subscribe("/releases", function(data) {
      add_to_table(data);
   });
});

function add_to_table(data){
    var json_obj = jQuery.parseJSON(data);
    var $content_table = $('#content_table');
    if ($content_table.find('tr').length >= 10 ) {
        $content_table.find("tr:last").remove();
    }
    $("#header").after("<tr><td>" + json_obj[0].title+ "</td><td>" + json_obj[0].site + "</td><td>" + json_obj[0].released_at + "</td></tr>");
}
All in all a nice little challenge. I have not had a chance to try it out beyond my home network yet so I am not sure how performant the solution would be.

Railscasts used for this:
Faye
Sidekiq