Active Jobの導入手順と、Active Job周りのRSpecの書き方をちゃんと理解していなかったので、英語の勉強も兼ねて、
『Active Job Basics — Ruby on Rails Guides』
を読んでみました!
🚌 Active Jobとは
Active Jobはジョブを宣言し、バックエンドでキュー操作を抽象化して実行するためのフレームワーク。
🗻 ジョブの作成
ジョブの作成コマンドはこちら。
$ bin/rails generate job guests_cleanup invoke test_unit create test/jobs/guests_cleanup_job_test.rb create app/jobs/guests_cleanup_job.rb
|
作成されたJobはこんな感じ。
class GuestsCleanupJob < ActiveJob::Base queue_as :default rescue_from(ActiveRecord::RecordNotFound) do |exception| end before_enqueue do |job| end around_perform do |job, block| block.call end
def perform(*guests) end end
|
🍣 Callbackの種別
- before_enqueue => キューにセットする前に呼び出される
- around_enqueue => キューにセットする前後で block を受け取り、呼び出す
- after_enqueue => キューにセットされた後に呼び出される
- before_perform => ジョブが実行される前に呼び出される
- around_perform => ジョブが実行される前後で block を受け取り、呼び出す
- after_perform => ジョブが実行された後で呼び出される
🎃 ジョブの登録方法
GuestsCleanupJob.perform_later(guest)
GuestsCleanupJob.set(wait_until: Date.tomorrow.noon).perform_later(guest)
GuestsCleanupJob.set(wait: 1.week).perform_later(guest)
|
😎 設定
module YourApp class Application < Rails::Application config.active_job.queue_name_prefix = Rails.env config.active_job.queue_adapter = :sidekiq end end
|
😼 RSpecの書き方
次のようにテストできるそうです。
RSpec.configure do |config| config.include ActiveJob::TestHelper config.include ActiveSupport::Testing::TimeHelpers ... end
|
class NotificationJob < ActiveJob::Base queue_as :default
def perform(msg) end end
|
class Message < ActiveRecord::Base def notification NotificationJob.set(wait: 5.seconds).perform_later body end end
|
require 'rails_helper'
describe Message, '#notification' do let(:message) { Message.new(body: 'Hello world!') }
it '5秒後に NotificationJob のキューにセットされる' do time = Time.current
travel_to(time) do assertion = { job: NotificationJob, args: ['Hello world!'], at: (time + 10.seconds).to_i, } assert_enqueued_with(assertion) { message.ping } end end end
|
🚜 (参考) GlobalID
Active Job以前は次のようにclasss, idを渡してActive Recordのオブジェクトを取得して、
からメソッドを実行していた。
class TrashableCleanupJob < ActiveJob::Base def perform(trashable_class, trashable_id, depth) trashable = trashable_class.constantize.find(trashable_id) trashable.cleanup(depth) end end
|
現在はこんな風に書いておくだけでActive Job側で良しなに対応してくれる。
class TrashableCleanupJob < ActiveJob::Base def perform(trashable, depth) trashable.cleanup(depth) end end
|
これは、Rails 4.2から実装された #gid
と #sgid
の効果によるもの。
gid = Friend.first.gid => # gid.app => "activejob-example" gid.model_name => "Friend" gid.model_class => Friend(id: integer, name: string, email: string...) gid.model_id => "1" gid.to_s => "gid://activejob-example/Friend/1"
sgid = Friend.first.sgid => # sgid.to_s => "BAh7CEkiCGdpZAY6BkVUSSIlZ2lkOi8vYWN0aXZl..."
|
これは知らなかったけど便利な機能。
🎳 (参考) Active Job adapters
Active Job adaptersの例。
|-------------------|-------|--------|------------|------------|---------|---------| | | Async | Queues | Delayed | Priorities | Timeout | Retries | |-------------------|-------|--------|------------|------------|---------|---------| | Backburner | Yes | Yes | Yes | Yes | Job | Global | | Delayed Job | Yes | Yes | Yes | Job | Global | Global | | Qu | Yes | Yes | No | No | No | Global | | Que | Yes | Yes | Yes | Job | No | Job | | queue_classic | Yes | Yes | Yes* | No | No | No | | Resque | Yes | Yes | Yes (Gem) | Queue | Global | Yes | | Sidekiq | Yes | Yes | Yes | Queue | No | Job | | Sneakers | Yes | Yes | No | Queue | Queue | No | | Sucker Punch | Yes | Yes | No | No | No | No | | Active Job Inline | No | Yes | N/A | N/A | N/A | N/A | |-------------------|-------|--------|------------|------------|---------|---------|
|
🐹 (参考) Action Mailerとの連携
Action Mailerの #deliver_later
は内部でActive Jobを使っている。
UserMailer.welcome(@user).deliver_now
UserMailer.welcome(@user).deliver_later
|
🐰 (参考) Action Mailerの #deliver_laterに関する処理
rails/message_delivery.rb at v5.0.0.beta3 - rails/rails
🐮 参考リンク
🖥 VULTRおすすめ
「VULTR」はVPSサーバのサービスです。日本にリージョンがあり、最安は512MBで2.5ドル/月($0.004/時間)で借りることができます。4GBメモリでも月20ドルです。
最近はVULTRのヘビーユーザーになので、「ここ」から会員登録してもらえるとサービス開発が捗ります!