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
just came here to say your blog name is fantastic
ReplyDeleteReally nice blog post.provided a helpful information.I hope that you will post more updates like thisRuby on Rails Online Training
ReplyDelete