1 簡介
Active Job 是用來宣告任務,並把任務放到多種佇列後台執行的框架。這些任務可以是平常的系統定時清理、收費方式改變通知、或是定時寄送郵件等任務。任何可以細分的工作與同步執行的事情都可以用 Active Job 來做。
2 Active Job 存在目的
主要確保 Rails 應用程式有個一致的背景任務框架,不做背景任務,要即時執行也可以。接著便可以有基於 Active Job 打造的功能、Gem 誕生,而無需擔心各種佇列後台,像是 Delayed Job 和 Resque 之間的 API 差異。選擇佇列後台變成一種運維方面的考量,而切換後台也無需修改任務本身的實作。
3 新建任務
本節提供建立任務,將任務加入排程的詳細教學。
3.1 建立任務
Active Job 提供了 Rails 產生器來建立任務。以下會在 app/jobs
建立一件新任務:
$ bin/rails generate job guests_cleanup invoke test_unit create test/jobs/guests_cleanup_job_test.rb create app/jobs/guests_cleanup_job.rb
也可以建立跑在特定佇列上的任務:
$ bin/rails generate job guests_cleanup --queue urgent
可以看出來,建立任務就和使用其他的 Rails 產生器一樣簡單。
若不想使用產生器,也可以自己在 app/jobs
下建立檔案,只要確保任務是繼承自 ActiveJob::Base
的類別即可。
以下是任務的程式範例:
class GuestsCleanupJob < ActiveJob::Base queue_as :default def perform(*args) # Do something later end end
3.2 任務排程
將任務加入排程:
# Enqueue a job to be performed as soon the queueing system is free. MyJob.perform_later record
# Enqueue a job to be performed tomorrow at noon. MyJob.set(wait_until: Date.tomorrow.noon).perform_later(record)
# Enqueue a job to be performed 1 week from now. MyJob.set(wait: 1.week).perform_later(record)
就這麼簡單!
4 執行任務
若無設定連接器,任務會即刻執行。
4.1 後台
Active Job 內建支援多種佇列後台的連接器(Sidekiq、Resque、Delayed Job 等)。完整連接器列表請見 ActiveJob::QueueAdapters 的 API 文件。
4.2 切換後台
切換後台的連接器非常簡單:
# be sure to have the adapter gem in your Gemfile and follow the adapter specific # installation and deployment instructions Rails.Application.config.active_job.queue_adapter = :sidekiq
5 佇列
多數的連接器都支持多種佇列。用 Active Job 可以將任務放到特定的佇列裡執行:
class GuestsCleanupJob < ActiveJob::Base queue_as :low_priority #.... end
預設佇列名稱的前綴為 \_
。可以在 application.rb 修改
config.active_job.queue_name_delimiter` 來修改:
# config/application.rb module YourApp class Application < Rails::Application config.active_job.queue_name_prefix = Rails.env config.active_job.queue_name_delimiter = '.' end end # app/jobs/guests_cleanup.rb class GuestsCleanupJob < ActiveJob::Base queue_as :low_priority #.... end # Now your job will run on queue production_low_priority on your # production environment and on beta_low_priority on your beta # environment
若需要更細緻的控制任務的執行,可以傳 :queue
給 #set
方法。
MyJob.set(queue: :another_queue).perform_later(record)
要在任務層級控制佇列,可以傳一個區塊給 queue_as
。區塊會在任務的上下文裡執行(也就是拿的到 `self.arguments),記得要回傳佇列的名稱:
class ProcessVideoJob < ActiveJob::Base queue_as do video = self.arguments.first if video.owner.premium? :premium_videojobs else :videojobs end end def perform(video) # do process video end end ProcessVideoJob.perform_later(Video.last)
確保後台程式知道佇列的名稱是什麼。某些後台可能需要明確指定佇列。
6 回呼
Active Job 在任務生命週期裡的每個階段都有提供 hooks。回呼允許在任務生命週期裡觸發事件來執行程式邏輯。
6.1 可用的回呼
before_enqueue
around_enqueue
after_enqueue
before_perform
around_perform
after_perform
6.2 用法
class GuestsCleanupJob < ActiveJob::Base queue_as :default before_enqueue do |job| # do something with the job instance end around_perform do |job, block| # do something before perform block.call # do something after perform end def perform # Do something later end end
7 ActionMailer
現代網路應用最常見的任務之一是在請求響應週期之外發送 Email,減去使用者等待的時間。Active Job
已與 Action Mailer 整合,異步寄送信件只需使用 deliver_later
即可:
# If you want to send the email now use #deliver_now UserMailer.welcome(@user).deliver_now # If you want to send the email through Active Job use #deliver_later UserMailer.welcome(@user).deliver_later
8 GlobalID
Active Job 支持使用 GlobalID 作為參數。這使得任務可以傳入 Active Record 物件,而不只是需要額外處理的類別名稱或 ID。使用類別和 ID 的任務看起來會像是:
class TrashableCleanupJob def perform(trashable_class, trashable_id, depth) trashable = trashable_class.constantize.find(trashable_id) trashable.cleanup(depth) end end
可以傳入 Active Record 物件來簡化:
class TrashableCleanupJob def perform(trashable, depth) trashable.cleanup(depth) end end
以上對任何混入 GlobalID::Identification
的類都有效,Active Model 的類別預設皆有混入 GlobalID::Identification
。
9 Exceptions
Active Job 提供捕捉任務執行期間發生異常的方法:
class GuestsCleanupJob < ActiveJob::Base queue_as :default rescue_from(ActiveRecord::RecordNotFound) do |exception| # do something with the exception end def perform # Do something later end end
反饋
歡迎幫忙改善指南的品質。
如發現任何錯誤之處,歡迎修正。開始貢獻前,可以先閱讀貢獻指南:文件。
翻譯如有錯誤,深感抱歉,歡迎 Fork 修正,或至此處回報。
文章可能有未完成或過時的內容。請先檢查 Edge Guides 來確定問題在 master 是否已經修掉了。再上 master 補上缺少的文件。內容參考 Ruby on Rails 指南準則來了解行文風格。
最後,任何關於 Ruby on Rails 文件的討論,歡迎至 rubyonrails-docs 郵件論壇。