2

I developed a RoR app that does some file processing in the background using resque-status.

I want to be able to display a CSS progress bar of the percentage status of the background job.

Is there a way to get the status of the job from the view (in real time) so I can change the value of a progress bar?

xxbinxx
  • 1,527
  • 11
  • 18
astronomotrous
  • 431
  • 1
  • 3
  • 12

1 Answers1

2

I have been considering this myself!


Push

You'll want to use something called push technology (the same as iPhone "Push Notifications"). This will give you the ability to send specific updates to your front-end.

Let me explain the issue, and how to resolve it...

The issue you have is that sending persistent updates is not within the remit of Rails, or HTTP for that matter. These are both built on the stateless protocol pattern, meaning that each request is on a clean slate.

This means that unless you open a persistent connection (from which you can specify different data attributes), you will only be able to send one-time updates, through asynchronous requests


Persistence

In order to "track progress", you need to create a system which firstly pushes your data (so you need a way to receive that data), and then you need to be able to process any of the pushed updates you'll receive. This is how you'll be able to create the "look" of a progress bar.

There are two ways to achieve this:

  1. SSE's
  2. Websockets

Both of these have a very simple way of working (you can see here: What are Long-Polling, Websockets, Server-Sent Events (SSE) and Comet?)

They essentially give you the ability to connect your front-end DOM (via JS) to a backend "push" system. This will then allow your JS to process any of the updates sent from your backend to your "listening" JS calls.

I won't go into specifics about SSE / Websockets, apart from saying that websockets are the best solution - they are truly persistent. SSE's just use ajax long-polling to your controller endpoint, highly inefficient & less secure.

--

Pushing

In order to achieve the "progress bar" type interface, you'll want to consider the following pattern:

  1. Your user's DOM connects to your endpoint using SSE's / Websockets
  2. Using the pub/sub pattern, you'll have a channel for each user
  3. Send push notifications to the respective channels

I would recommend using a system called Pusher for this (no affiliation). It's a websocket interface, connecting your front-end to the backend controller methods of your system

This will allow you to perform the following:

#app/assets/stylesheets/application.css.sass
.progress
   background: #ccc
   .bar
      background: #f0f

#app/workers/your_job_worker.rb
class YourJobWorker
  include Resque::Plugins::Status

  def perform
    # send update to pusher here
  end

end

#app/assets/javascripts/application.js
var pusher = new Pusher('***');
var channel = pusher.subscribe('*****');
channel.bind('progress', function(data) {
    $(".bar .progress").css("width", data + "%");
});

Obviously a very rough outline for you - hopefully will explain the methodology of how you'd tackle this issue.

Community
  • 1
  • 1
Richard Peck
  • 76,116
  • 9
  • 93
  • 147
  • 2
    Amazing, this seems to be the answer I have been tirelessly looking for. I will attempt to implement this ASAP and will update it to the correct answer afterwards. Thanks! – astronomotrous Sep 03 '14 at 16:21