Skip to content

allow your users to wait for the completion of your `ActiveJob`

License

Notifications You must be signed in to change notification settings

jedld/active_waiter

 
 

Repository files navigation

ActiveWaiter

Build Status

A simple mechanism allowing your users to wait for the completion of your ActiveJob

Scenario

You have an export PDF feature that you've implemented directly in the controller action.

As data grows, your HTTP request takes longer and starts timing out. So you decide to move the PDF generating code into a background job.

def index
  respond_to do |format|
    format.html
    format.pdf {
      ExportPdfJob.perform_later(@things, current_user)
      redirect_to :back, notice: "We'll email your PDF when it's done!"
    }
  end
end

But how do you get that PDF into the hands of your users now? Email? Push notification? Manual reload?

You have no PDF ready for download (yet). Please reload.

Solution

Let ActiveWaiter enqueue that job instead and redirect to its progress tracking page.

def index
  respond_to do |format|
    format.html
    format.pdf {
      uid = ActiveWaiter.enqueue(ExportPdfJob, @things, current_user)
      redirect_to active_waiter_path(id: uid)
    }
  end
end
# routes.rb
mount ActiveWaiter::Engine => "/active_waiter"

When the job completes, the user will be redirected to the url returned by the job. However, if you want the user to be presented with a download link, add download: 1 params instead

redirect_to active_waiter_path(id: uid, download: 1)

active_waiter mov

And we need to add a bit of code into your ActiveJob class

    1. add include ActiveWaiter::Job
    1. return a url from your perform method to link to the result page (or file)
class ExportPdfJob < ActiveJob::Base
  queue_as :default

  # (1)
  include ActiveWaiter::Job

  def perform(things, current_user)
    count = things.count.to_f
    files = []
    things.each_with_index do |thing, index|
      files << generate_pdf(thing)

      # (a)
      update_active_waiter percentage: (100 * (index+1) / count)
    end

    # (2)
    upload(combine(files)).s3_url
  rescue Exception => e

    # (b)
    update_active_waiter error: e.to_s
  end
end

Optionally, you can also

  • a) report progress while your job runs, using update_active_waiter(percentage:)
  • b) report if there were any errors, using update_active_waiter(error:)

Configuration

By default, ActiveWaiter uses a simple Bootstrap layout. To use your application's layout, configure:

ActiveWaiter.configure do |config|
  config.layout = "layouts/application"
end

Next, prefix any routes used in your application's layout with main_app., e.g. main_app.sign_in_path.

This is required because ActiveWaiter is a Rails Engine mounted into your application, and it doesn't know about the routes declared within your application.

Exceptions

When your job gets an exception, the error message will be written in the error message and passed along to the user. If your job has a method suppress_exceptions that returns a truthy value (default false), ActiveWaiter::Job will swallow the exception and not raise it - this means there will be no retry by ActiveJob.

Common Jobs

ActiveWaiter::EnumerableJob

If you need to wait, you're likely doing one thing slowly or many things. For the latter case, you can just include ActiveWaiter::EnumerableJob and add a few interface methods

def before(*args); end # called once with arguments of `perform`
def enumerable; [] end # an Enumerable interface
def items_count; 1 end # called 0-n times, depending on enumerable
def foreach(item); end # called 0-n times, depending on enumerable
def after;         end # called once
def result;        end # called once

Here's an example from our test code, that will generate an array of range 0...count and return the sum of all the numbers

class LoopJob < ActiveJob::Base
  include ActiveWaiter::EnumerableJob

  attr_accessor :items_count, :enumerable, :result

  def before(count)
    @items_count = count
    @enumerable = count.times
    @result = 0
  end

  def foreach(item)
    @result += item
  end
end

About

allow your users to wait for the completion of your `ActiveJob`

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Ruby 74.3%
  • HTML 18.8%
  • CSS 3.7%
  • JavaScript 3.2%