Sidekiq Job Monitor
This gem allows you to easily monitor your jobs progression from your client.
This is often useful when the user has to wait for a specific job to complete to access some produced data.
The original use case was to allow users to see a "work in progress" modal while a big document was being generated, and then redirect them to download it when the job has completed.
The gem plugs into Sidekiq's job processor as a middleware to track the job progress and make it available through an JSON endpoint.
There's also a simple javascript client that allows you to hook into the complete and failed events.
Installation
Add to your Gemfile and bundle install:
gem 'sidekiq-job_monitor'Mount the engine in your routes.rb :
mount Sidekiq::JobMonitor::Engine => '/job-monitor', as: :job_monitorThen load the js library by adding the following to your application.js :
//= require sidekiq-job_monitorUsage
The supported workflow for the gem is the following :
- The user requests a document that need time to be processed
- The server enqueues a sidekiq job in high priority queue and returns a waiting message in the form of a modal (for instance)
- The client polls the server to know when the job is done
- When the job is done, the server returns data to the client so that it can take some action to deliver the document
1. Requesting the document
Add a link to the job starting endpoint as a remote link :
<%= link_to 'Download report', build_report_path(@report), remote: true, data: { :'job-monitor-link' => true }
Initialize the javascript client and make it handle the main events :
$(function() {
$('[data-job-monitor-link]').each(function(i, el) {
$(el).sidekiqJobMonitor({
onStart: function($el) {
// If you return a modal box from the server, initialize it
$el.appendTo('body').modal();
// Handle the "complete" event and redirect the user to a target
// URL where it will be able to download the document
$el.on('complete', function(e, monitor, data) {
window.location.href = data.url;
});
// You can also stop monitoring the progress, for instance when the
// modal is closed :
$el.on('hide', function() {
$el.trigger('stop');
});
}
});
});
});2. The server enqueues a sidekiq job in high priority queue and returns a waiting message
Enqueue a job with a worker as usual, and store the Job ID in the controller
class ReportsController
def build
@job_id = MyReportWorker.perform_async(params[:id])
render layout: false
end
endRender a modal and return the monitoring URL as the main returned node's
[data-monitor-url] attribute, with the URL returned by job_monitor.job_progress_path(job_id) :
<div class="modal" data-monitor-url="<%= job_monitor.job_progress_path(@job_id) %>">
<!-- Snip -->
Please wait ...
<!-- Snip -->
</div>3. The client polls the server to know when the job is done
This part is already covered by the javascript code we wrote in step 1.
All you need is the correct plugin initialization and returning the
data-monitor-url attribute on the main returned node.
4. The client polls the server to know when the job is done
When the job is done, a javascript complete event is triggered on the modal.
We already handled that in step 1.
All we need now is to provide the url field in the data object returned by
the server upon job completion.
To do so, we add the #monitoring_data method to our worker class.
This method takes the exact same arguments as the #perform method, plus
the current job state (pending, processing, complete or failed) as the last
argument.
class MyReportWorker
include Sidekiq::Worker
def perform(report_id)
# Your worker logic here as usual ...
end
def monitoring_data(report_id, state)
# Pseudo logic to get the desired URL
{ url: Report.find(report_id).document_url } if state == 'complete'
end
endThose fields will be added to the data hash returned by the server as JSON
and passed to the complete event callback as the last argument.
Licence
This project rocks and uses MIT-LICENSE.