开发中涉及到调用三方服务API,运行时间长,结果不需要实时反馈给用户这样的任务,都可以使用异步处理。常见的场景包括:发邮件和短信、图片处理、定时清理等、爬虫。
后端处理软件可以自行选择这里选择了sidekiq
Active Job 设置
全局设定
class Application < Rails::Application
# ...
config.active_job.queue_adapter = :sidekiq
end
局部设定
class GuestsCleanupJob < ApplicationJob
self.queue_adapter = :resque
#....
end
# 现在,这个作业使用 `resque` 作为后端队列适配器
# 把 `config.active_job.queue_adapter` 配置覆盖了
之后我们可以根据需要生成相应的job
rails generate job Example
这条命令会生成/app/jobs/example_job.rb
class ExampleJob < ActiveJob::Base
# Set the Queue as Default
queue_as :default
def perform(*args)
# Perform Job
end
end
怎么使用这个job呢?
ExampleJob.perform_later args
这样这个job就会被加入到队列中,加入到队列中就会被等待执行。如果出现了错误,sidekiq会在之后进行重试。
还有几种入队作业
# 入队作业,作业在队列系统空闲时立即执行
GuestsCleanupJob.perform_later guest
# 入队作业,在明天中午执行
GuestsCleanupJob.set(wait_until: Date.tomorrow.noon).perform_later(guest)
# 入队作业,在一周以后执行
GuestsCleanupJob.set(wait: 1.week).perform_later(guest)
# `perform_now` 和 `perform_later` 会在幕后调用 `perform` 因此可以传入任意个参数
GuestsCleanupJob.perform_later(guest1, guest2, filter: 'some_filter')
# `perform_now` 代码会立即执行,在这开发环境会很实用。
MyJob.new(*args).perform_now
MyJob.perform_now("mike")
队列
多数适配器支持多个队列,默认使用的 queue_name 是 default。Active Job 允许把作业调度到具体的队列中:
class GuestsCleanupJob < ApplicationJob
queue_as :low_priority
#....
end
队列名称可以使用 application.rb 文件中的 config.active_job.queue_name_prefix 选项配置前缀。
默认的队列名称前缀分隔符是 _。这个值可以使用 application.rb 文件中的 config.active_job.queue_name_delimiter 选项修改。
队列有优先级这个属性,优先级高的会被先执行。类方法 queue_with_priority 可以进行设置。
# 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_job.rb
class GuestsCleanupJob < ApplicationJob
queue_as :low_priority
queue_with_priority 50
def perform(post)
post.to_feed!
end
end
# 在生产环境中,作业在 production.low_priority 队列中运行
# 在交付准备环境中,作业在 staging.low_priority 队列中运行
控制
Active Job 在作业的生命周期内提供了多个钩子。回调用于在作业的生命周期内触发逻辑。可用的回调:
- before_enqueue
- around_enqueue
- after_enqueue
- before_perform
- around_perform
- after_perform
class GuestsCleanupJob < ApplicationJob
queue_as :default
before_enqueue do |job|
# 对作业实例做些事情
end
around_perform do |job, block|
# 在执行之前做些事情
block.call
# 在执行之后做些事情
end
def perform
# 稍后做些事情
end
end