delayed_job

Delayed Job

AUG 21ST, 2012 | COMMENTS

Delayed Job 是一套非同步排程套件。

有時候,當必須執行 process time 較久的 request 時,會因為要等待此 request 執行完畢而無法再做其他的 request 導致效率低落,此時如果把 process time 較久的 request 移到背後去執行,那就可以把原本要等候的時間拿來處理其他事。

Rails 目前已有許多可執行背景作業的套件,而當中的 Delayed Job 其特點是使用與此 application 相同的資料庫,並簡化許多的設定。此外,Delayed Job 提供了一個非常簡單的 interface,在呼叫任何方法之前加上 delay就可以改為背景作業。以下將以寄信作為範例:

安裝

Delayed Job 有許多不同的套件,由於此範例使用的是 ActiveRecord,因此選擇 delayed_job_active_record 套件。

/Gemfile
1
gem 'delayed_job_active_record'
$ bundle install

安裝套件:

$ rails g delayed_job:active_record
    create  script/delayed_job
    chmod  script/delayed_job
    create  db/migrate/20120109185353_create_delayed_jobs.rb

由於會產生 migration 檔案,因此要再執行 rake db:migrate 來產生資料表。

設定完了之後,就執行 Delayed Job 的 Rake task:jobs:work 以開始背景作業。

$ rake jobs:work
[Worker(host:noonoo.home pid:3031)] Starting job worker
使用

假設此範例的寄信需要花費 10 秒鐘(用 sleep 來模擬):

/app/controllers/newsletters_controller.rb
1
2
3
4
5
6
def deliver
  @newsletter = Newsletter.find(params[:id])
  sleep 10 # simulate long newsletter delivery
  @newsletter.update_attribute(:delivered_at, Time.zone.now)
  redirect_to newsletters_url, notice: "Delivered newsletter."
end

首先將這段寄信的程式碼包到 model 裡頭,改為呼叫 Newsletter 的 deliver 方法 :

/app/controllers/newsletters_controller.rb
1
2
3
4
5
def deliver
  @newsletter = Newsletter.find(params[:id])
  @newsletter.deliver
  redirect_to newsletters_url, notice: "Delivered newsletter."
end
/app/models/newsletter.rb
1
2
3
4
5
6
class Newsletter < ActiveRecord::Base
  def deliver
    sleep 10 # simulate long newsletter delivery
    update_attribute(:delivered_at, Time.zone.now)
  end
end

用 deliver 方法包起來之後,就可以呼叫 delay 方法將寄信丟到背景作業了。

/app/controllers/newsletters_controller.rb
1
2
3
4
5
def deliver
  @newsletter = Newsletter.find(params[:id])
  @newsletter.delay.deliver
  redirect_to newsletters_url, notice: "Delivering newsletter."
end

這段程式碼會增加一筆 record 到 delayed_jobs 資料表當中,並告訴 Delayed Job 要用 deliver 方法來處理這個 instance 。

簡化

上述那段程式碼可以更加簡化,不使用整個 newsletter instance,而是透過傳遞 id 來使用 Newsletter 類別:

/app/controllers/newsletters_controller.rb
1
2
3
4
def deliver
  Newsletter.delay.deliver(params[:id])
  redirect_to newsletters_url, notice: "Delivering newsletter."
end
/app/models/newsletter.rb
1
2
3
4
5
6
7
8
9
10
class Newsletter < ActiveRecord::Base
  def self.deliver(id)
    find(id).deliver
  end

  def deliver
    sleep 10 # simulate long newsletter delivery
    update_attribute(:delivered_at, Time.zone.now)
  end
end
Delay 方法的其他選項

Delayed Job 針對 Delay 方法提供了許多選項,其中一項是 queue,透過給定名稱的 queue,就可以指派不同的 worker 去處理對應的 queue。

/app/controllers/newsletters_controller.rb
1
Newsletter.delay(queue: "newsletter").deliver(params[:id])

另一個有用的選項是 priority,預設值是 0 ,表示優先處理。數字越小則優先處理程度越高,可設為負數。 此外,run_at 則是可以設定某個時間點再處理。

/app/controllers/newsletters_controller.rb
1
Newsletter.delay(queue: "newsletter", priority: 28, run_at: 5.minutes.from_now).deliver(params[:id])

如果某個方法每次都要用 delay 來執行,就可以考慮在該類別裡面加上 handle_asynchronously,後面以 symbol 加上要呼叫的方法:

1
2
3
4
5
6
class LongTasks
  def send_mailer
    # Some other code
  end
  handle_asynchronously :send_mailer, :priority => 20
end
錯誤處理

Delayed Job 也支援錯誤處理。可以設定成失敗後,會再次嘗試執行,但須注意會不會對後續其他作業產生影響。相關設定如:

/config/initializers/delayed_job_config.rb
1
2
Delayed::Worker.max_attempts = 5
Delayed::Worker.delay_jobs = !Rails.env.test?

此段是針對 Delayed::Worker 來做設定。如果出現錯誤,就再嘗試最多 5 次;如果目前環境是 test 就停止執行。

在 Production 環境執行 Delayed Job

到目前為止,是透過 rake jobs:work 來執行 Delayed Job,但在 production 環境下,要改成執行 script 資料夾裡頭的 delayed_job script:

$ script/delayed_job start

如果在 development 環境下執行,可能會跳出錯誤訊息,說要使用 daemons gem:

/Gemfile
1
gem 'daemons'
$ bundle install

再次輸入就會顯示執行成功:

$ script/delayed_job start
delayed_job: process with pid 1672 started.

如果要停止,就輸入:

$ script/delayed_job stop

若要在 Capistrano 上使用 Delayed Job,可至 wiki 查看。
若要使用 web 方式來監控 job queue,可使用 delayed_job_web gem。
其他非同步排成套件還有 ResqueSidekiq 等。

source: RailsCasts

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值