Ruby rails: jobs

From wikinotes
Revision as of 20:43, 19 September 2021 by Will (talk | contribs) (→‎Priority)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

ActiveJob is an abstraction of jobs that can be placed in a queue and run asynchronously.
Rails ships with an in-memory queue (jobs lost on reset), but includes adapters for several queue systems.

NOTE:

The official guide for jobs is really good, consult that first. https://guides.rubyonrails.org/active_job_basics.html

Documentation

official guide https://guides.rubyonrails.org/active_job_basics.html
official testing guide https://guides.rubyonrails.org/testing.html#testing-jobs
API docs https://api.rubyonrails.org/classes/ActiveJob.html
API Queue Adapters https://api.rubyonrails.org/classes/ActiveJob/QueueAdapters.html

Locations

app/jobs/{jobname}_job.rb job itself
test/jobs/{jobname}_job_test.rb job test

Commandline

rails g job guests_cleanup  # -> GuestsCleanupJob

Example

# app/jobs/user_cleanup_job.rb
class UserCleanupJob < ApplicationJob
  queue_as :default
 
  def perform(*users)
    # ...
  end
end

Enqueue a job

UserCleanupJob.perform_later(user1, user2)
UsersCleanupJob.set(wait_until: Date.tomorrow.noon).perform_later(user)
UsersCleanupJob.set(wait: 1.week).perform_later(user)

Queue Backend

Rails ships with non-persistent in-memory queue.
You probably want to use an adapter for a backend persists application restarts.

Common Backends

sidekiq
resque
sneakers
sucker punch
queue classic
delayed job

Set Backend

Globally

# config/application.rb

module YourApp
  class Application < Rails::Application
    config.active_job.queue_adapter = :sidekiq  # <---
  end
end

Per-Job

class GuestsCleanupJob < ApplicationJob
  self.queue_adapter = :resque  # <---
end

Syntax

Enqueueing Jobs

MyJob.perform_now(arg1: "foo")    # enqueue job
MyJob.new(arg1: "foo").enqueue    # enqueue job
MyJob.perform_later(arg1: "foo")  # perform synchronously where called

Priority

You can set the default priority, queue etc on the class.
or you can override it when you enqueue it.

Set default priority

class MyJob < ApplicationJob
  queue_with_priority 50

  def perform(message)
    puts("hi there")
  end
end

Override priority at enqueue time

MyJob
  .set(priority: 50)
  .perform_later("hi there")

Arguments/DataTypes

Datatypes used in arguments must be serializable in order to be used in jobs.
ActiveJob supports the following types, and also exposes an interface
so you can manage serialization/deserialization of custom types.

Natively supported DataTypes

Basic types (NilClass, String, Integer, Float, BigDecimal, TrueClass, FalseClass)
Symbol
Date
Time
DateTime
ActiveSupport::TimeWithZone
ActiveSupport::Duration
Hash (Keys should be of String or Symbol type)
ActiveSupport::HashWithIndifferentAccess
Array

Custom Serializer for your DataTypes

# define serializer (where?)

class MoneySerializer < ActiveJob::Serializers::ObjectSerializer
  # Checks if an argument should be serialized by this serializer.
  def serialize?(argument)
    argument.is_a? Money
  end

  def serialize(money)
    super("amount" => money.amount, "currency" => money.currency)
  end

  def deserialize(hash)
    Money.new(hash["amount"], hash["currency"])
  end
end

Enable serializer for activejobs

# config/application.rb

module Project
  class Application < Rails::Application
    config.active_job.custom_serializers << MoneySerializer
  end
end

Exceptions

You can assign behaviour to exceptions encountered during the execution of a job.
You may want to log/reraise, discard, or retry on specific exceptions.

class GuestsCleanupJob < ApplicationJob
  queue_as :default

  # retry/discard
  retry_on MyRetryError
  discard_on MyCancelError

  # handle exception
  rescue_from(ActiveRecord::RecordNotFound) do |exception|
    # ...
  end

  def perform
    # ...
  end
end

Callbacks

before_enqueue
around_enqueue
after_enqueue
before_perform
around_perform
after_perform

Queue Contents

ActiveJob::Base.queue_adapter.enqueued_jobs  # jobs in the queue

Extensions

ruby job-iteration