Active Job

From Expertiza_Wiki
Revision as of 22:11, 5 February 2016 by Schen35 (talk | contribs) (→‎Examples)
Jump to navigation Jump to search

Introduction

Active Job is a framework that helps developers writing codes and run them on the background automatically under different scenarios. Jobs can vary from schedule newsletter, follow-up emails to database housekeeping. It’s an interface that adapts different queueing backends like Backburner[1], Delayed Job[2], Qu[3] and so on. <ref name= "Active-Job-Basics">Rails Guides “Active Job Basics” </ref> Overall, Active Job is a interface which you can work with common queues.

Ruby On Rails versions support Active Job

Version history
Version Date
4.2 2014/12/19
4.2.5 2015/11/13







Active Job adapters<ref name="Active-Job-Adapter">Active Job Adapter"Active Job Adapter" </ref>

How to use <ref>http://guides.rubyonrails.org/active_job_basics.html</ref>

We will introduce how to creating a job and and how to add the job into a queue. <ref name= "Active-Job-Basics">Rails Guides “Active Job Basics” 2014</ref>

Download

With RubyGems you can install the Active Job into your computer:

$ gem install activejob

Souce code of Active Job available on GitHub, as part of Rails.<ref> GitHub “Active Job -- Make work happen later” 2015 </ref>

Create a Job

In Active Job, a process which is inserted in a queue and waiting for carry out is called “Job”. It’s possible to generate a Job using the Generator provided by Rails. You can create a job in app/jobs, with the name “update_wiki”, by doing the following.

$ bin/rails generate job update_wiki
  invoke  test_unit
  create  test/jobs/update_wiki_job_test.rb
  create  app/jobs/update_wiki_job.rb

Active Job provides the ability to run your Job on a specific queue by create a job as following:

$ bin/rails generate job update_wiki --queue urgent

Files inside of app/jobs can be created manually, instead of using a generator. In Rails 4.2 an ActiveJob class inherits from ActiveJob::Base. In Rails 5.0, it has changed to now inherit from ApplicationJob. When upgrading from Rails 4.2 to Rails 5.0, an application_job.rb file is needed to be created in app/jobs/ and add the following content:<ref> Rails Guides “A Guide for Upgrading Ruby on Rails” 2015 </ref>

class ApplicationJob < ActiveJob::Base
end

In Rails 4.2 a Job class defined a perform method and set a “queue_as” value:

class UpdateWikiJob < ActiveJob::Base
  queue_as :default
 
  def perform(*wiki)
   # Do something later
  wiki.update_contents
  end
end

There is a perform method to be called when the job was first enqueued.

Adding a Job to the queue

If you wish your Job be processed as soon as the queuing system is free, you can enqueue a Job like:

UpdateWikiJob.perform_later wiki

Or you can add a Job be performed tomorrow at noon:

UpdateWikiJob.set(wait_until: Date.tomorrow.noon).perform_later(wiki)

If you want your Job be performed a week from now, most of the queueing backends ( Sidekiq , Delayed Job, etc. ) allow you to set a delay time.

UpdateWikiJob.set(wait: 1.week).perform_later(wiki)

Execution of Job

Active Job provides adapters for multiple queueing backends (Sidekiq, Resque, Delayed Job and others).<ref name= "Active-Job-Basics">Rails Guides “Active Job Basics” 2014</ref> Without setting any adapter, the job would be performed immediately.
Queueing backend can be set at: /config/application.rb, in this example we use the Sidekiq.

module YourApp
  class Application < Rails::Application
    # Be sure to have the adapter's gem in your Gemfile and follow
    # the adapter's specific installation and deployment instructions.
    config.active_job.queue_adapter = :sidekiq
  end
end

Play with Queues

Active Job allows to schedule the job to be processed on a specific queue, this became helpful as common adapters support multiple queues.

class UpdateWikiJob < ActiveJob::Base
  queue_as :low_priority
  #....
end

Queue name can be prefixed for all jobs using config.active_job.queue_name_prefixin application.rb:

# config/application.rb
module YourApp
  class Application < Rails::Application
    config.active_job.queue_name_prefix = Rails.env
  end
end
 
# app/jobs/update_wiki_job.rb
class UpdateWikiJob < ActiveJob::Base
  queue_as :low_priority
  #....
end
 
# Now your job will run on queue production_low_priority on your
# production environment and on staging_low_priority on your staging
# environment


You can control a job to run on a queue you like, by passing a :queue option to #set :

MyJob.set(queue: :another_queue).perform_later(record)

All the code snippets are referred from the source<ref name= "Active-Job-Basics">Rails Guides “Active Job Basics” 2014</ref>

Examples

In this section, some examples are provided to demonstrate how to use ActiveJob in practices.

Background Mail Sender

You can send emails asynchronously with Action Mailer which Active Job is already integrated in.<ref name= "Action-Mailer-Basics">Rails Guides “Action Mailer Basics” 2014</ref> Here in this example, we try to use Active Job with Action Mailer.

1. Getting started with Rails:<ref name= "Welcome_to_Rails">GitHub “Welcome to Rails” 2015</ref>

# Install Rails if you haven’t done it yet:
$ gem install rails

# Create a new Rails application, “myapp_activejob”
# is the name of the application:
$ rails new myapp_activejob

# Change your directory to myapp_activejob
$ cd myapp_activejob

Edit the Gemfile in the folder, add following into it:

gem 'responders'

Run “ $ bundle update “ and make sure “$ rails server” works.

2. Resque setup<ref name= "Download_Redis">Redis “Download Redis” 2016</ref>

We will use Resque as the enqueuing backend. You need to install Redis before you can run Resque. You can getting Redis with Homebrew:

$ brew install redis

Or you can download, extract and compile Redis with:<ref name= "Download_Redis">Redis “Download Redis” 2016</ref>

$ wget http://download.redis.io/releases/redis-3.0.7.tar.gz
$ tar xzf redis-3.0.7.tar.gz
$ cd redis-3.0.7
$ make

Redis does not officially support Windows, but you can find Redis on Windows by Microsoft Open Tech group.
Next get Resque be installed. To use resque with Active Job, we also need resque-scheduler. Add the following into Gemfile, and run “$ bundle install”.

gem 'resque'
gem 'resque-scheduler'

After the installation, create a Resque configuration file resque.rb in config/initializers/

#config/initializers/resque.rb

Resque.redis = Redis.new(host: 'localhost', post: 6379)
Resque.after_fork = Proc.new { ActiveRecord::Base.establish_connection }

As the Resque tasks and Resque Scheduler rake tasks are needed in this example, we need to create a resque.rake file in lib/tasks/:

#lib/tasks/resque.rake

require 'resque/tasks'
require 'resque/scheduler/tasks'

namespace :resque do
  task setup: :environment do
    ENV['TERM_CHILD'] ||= '1'
    ENV['QUEUE'] ||= '*'
    require 'resque'
    require 'resque-scheduler'
  end
end

3. Creating a Mailer<ref name= "Action-Mailer-Basics">Rails Guides “Action Mailer Basics” 2014</ref>

By doing the things above, we already have our Rails project and the Resque for queuing get set. Next we will creat a Mailer.

$ bin/rails generate mailer user_mailer

Create a method and a view for sending email.
In app/mailer/user_mailer.rb:

#app/mailers/user_mailer.rb

class UserMailer < ActionMailer::Base
  default from: 'from@example.com'

  def follow_up_email(email)
    mail(
      to: email,
      subject: 'We hope you are enjoying our app'
    )
  end
end

In app/views/user_mailer/follow_up_email.text

#app/views/user_mailer/follow_up_email.text

Hey, we saw that you recently signed up for our app.
We hope you're enjoying it!


4. Active Job

Create a configuration file active_job.rb in config/initializers/ , to set Resque as queue_adapter.

#config/initializers/active_job.rb

ActiveJob::Base.queue_adapter = :resque

Create a Job with generator.

$ bin/rails generate job follow_up_email

In the generated file app/jobs/user_registered_mailer_job.rb, define the perform method and set it’s queue_as.

#app/jobs/follow_up_email_job.rb

class FollowUpEmailJob < ActiveJob::Base
  queue_as :email

  def perform(email)
    UserMailer.follow_up_email(email).deliver_now
  end
end

Now we can use a UserController to put the job into the queue for later execution. Here we set the email to be sent one minute later for test.

$ bin/rails generate job follow_up_email
#app/controllers/users_controller.rb

class UsersController < ApplicationController
  def new
    @user = User.new
  end

  def create
    @user = User.create(user_params)
    FollowUpEmailJob.new(@user.email).deliver_later!(wait: 1.minute)
    # redirect somewhere
  end
end

Routes and view need to set to make it work.

#config/routes.rb

Rails.application.routes.draw do
  resources :users, only: [:new, :create]
end
#app/views/users/new.html.erb

<%= form_for @user do |f| %>
  <%= f.email_field :email %>
  <%= f.submit %>
<% end %>

5. Try execution

Before we try the mailer, we need a “mailcatcher” for the test. Add following into Gemfile and “$ bundle install”

gem 'mailcatcher'

To set the environment, add following things into config/environments/development.rb.

#config/environments/development.rb

Rails.application.configure do
  ...
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = { :address => "localhost", :port => 1025 }
end

Run it!

# Start mailcatcher
$ mailcatcher

# Start redis-server
$ redis-server

# Start resque:work
$ bundle exec rake resque:work

# Start resque:scheduler
$ rake environment resque:scheduler

# Finally start rails server
$ rails server

In your browser, view the Resque dashboard at http://0.0.0.0:5678. In another tab, visit http://127.0.0.1:1080 to see the Mailcatcher dashboard. Visit localhost:3000/users/new and sign up as a new user. One minute later you can see following in Resque scheduler:

resque-scheduler: [INFO] 2016-02-05T22:53:15+09:00: Processing Delayed Items

And in mailcatcher:

==> SMTP: Received message from '<from@example.com>' (315 bytes)

Yeah!

References

<references/>