1
votes

I am implementing background processing jobs in Rails using 'Sidekiq' gem which are run when a user clicks on a button. Since the jobs are run asynchronously, rails replies back instantly.

I want to add in a functionality or a callback to trigger a JavaScript popup to display that the job processing has finished.

Controller Snippet:

def exec_job
   JobWorker.perform_async(@job_id,@user_id)
   respond_to do |wants|
      wants.html {  }
      wants.js { render 'summary.js.haml' }
   end
end

Edit 1: I am storing the 'user_id' to keep a track of the user who triggered the job. So that I can relate the popup to this user.

Edit 2: The 'perform' method of Sidekiq does some database manipulation(Update mostly) and log creation, which takes time.

Currently, the user gets to know about the status when he refreshes the page later.

Edit 3(Solution Attempt 1):

I tried implementing 'Faye Push Notification' by using subscribe after successful login of user(with channel as user_id).

On the server side, when the job completes execution, I created another client to publish a message to the same channel (Using faye reference documents).

It is working fine on my desktop, i.e., I can see an alert popup prompting that the job has completed. But when I try testing using another machine on my local network, the alert is not prompted.

Client Side Script:

(function() {
    var faye = new Faye.Client('http://Server_IP:9292/faye');
    var public_subscription = faye.subscribe("/users/#{current_user.id}", function(data) {
        alert(data);
    });
});

Server Side Code:

EM.run {
  client = Faye::Client.new('http://localhost:9292/faye')
  publication = client.publish("/users/#{user.id}", 'Execution completed!')

  publication.callback do
    logger.info("Message sent to channel '/users/#{user.id}'")
  end

  publication.errback do |error|
    logger.info('There was a problem: ' + error.message)
  end
}
2
The concept of what you're trying to do is Push Notifications. This rails cast episode might help you out a bit: railscasts.com/episodes/260-messaging-with-fayefmendez
Thanks, I think I will try and work on a 'faye' solution. Probably, I would have to implement a server side push to channel. :)Vageesh Bhasin

2 Answers

0
votes

Rails 4 introduced the ActionController::Live module. This allows for pushing SSEs to the browser. If you want to implement this based on a database update you will need to look into configuring Postgresql to LISTEN and NOTIFY.

class MyController < ActionController::Base
  include ActionController::Live

  def stream
    response.headers['Content-Type'] = 'text/event-stream'
    100.times {
      response.stream.write "hello world\n"
      sleep 1
    }
  ensure
    response.stream.close
  end
end

Here is a good article on it: http://ngauthier.com/2013/02/rails-4-sse-notify-listen.html

0
votes

Thanks fmendez.

I looked at the suggestions given by other users and finally, I have implemented a 'Faye' based push notification by:

  1. Subscribing the user on successful login to a channel created using 'user_id'
  2. Replying to this channel from server side after job completion (By fetching user_id)

For better understanding(so that it may be helpful for others), check the edit to the question.