Active Job
commit信息:Fix typo | 提交者:rhombl4 | 提交时间:2020-10-30 | 版本:db5ff8d
Rails 4.2引进了Active Job。 Active Job是跟job runners交流的标准接口。可以配置Active Job与Sidekiq一起工作。
Active Job 设置
Active Job 的适配器必须设置为:sidekiq
,否则它将使用Rails设置的默认值:async
。这可以在config/application.rb
文件中设置:
class Application < Rails::Application
# ...
config.active_job.queue_adapter = :sidekiq
end
我们可以使用生成器来新建一个作业。
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
使用
可以将Jobs从任意地方加入到任务队列。我们可以使用以下代码往队列里添加作业:
ExampleJob.perform_later args
然后,Sidekiq将会为我们完成这个作业。当作业由于一些原因失败了,Sidekiq将照常重试它。
定制错误支持
在Rails 6.0.1之前,Active Job 不能充分并且轻松的支持Sidekiq的retry
功能。取而代之的是,当遇到特定的异常时,它有一个更简陋的抽象来编码重试。
class ExampleJob < ActiveJob::Base
retry_on ErrorLoadingSite, wait: 5.minutes, queue: :low_priority
def perform(*args)
# Perform Job
end
end
默认的Active Job重试方案(使用retry_on
)为5次重试,间隔为3秒。完成这些(大概需要15-30秒),Active Job将把这个作业踢回Sidekiq,然后Sidekiq的指数级回退重试功能将接管该作业。
自Sidekiq 6.0.1起,你可以在大于Rails 6.0.1版的Active Jobs里使用sidekiq_options
来配置标准的Sidekiq重试机制。
class ExampleJob < ActiveJob::Base
sidekiq_options retry: 5
def perform(*args)
# Perform Job
end
end
Active Mailer
Action Mailer 现在拥有一个名为 #deliver_later 的方法,该方法将异步发送email(在后台作业中发送你的email)。只要Active Job被设置为使用Sidekiq,我们就可以使用 #deliver_later 。不像Sidekiq,Active Job将使用全局ID序列化任何activerecord实例。 之后,该实例将被反序列化。
Mailers 被排队在mailers队列。不要忘了开启sidekiq来处理该队列:
bundle exec sidekiq -q default -q mailers
我们可以使用下面代码来发送一个基础信息给作业队列:
UserMailer.welcome_email(@user).deliver_later
当你想绕过作业队列来同步执行该作业时,你可以使用下面代码:
UserMailer.welcome_email(@user).deliver_now
使用Sidekiq,我们可以选择发送带有一定延迟的emails。我们也可以通过Active Job来做到这一点。
Sidekiq中延迟消息的旧语法:
UserMailer.delay_for(1.hour).welcome_email(@user.id)
UserMailer.delay_until(5.days.from_now).welcome_email(@user.id)
通过Active Job来延迟消息的新语法:
UserMailer.welcome_email(@user).deliver_later(wait: 1.hour)
UserMailer.welcome_email(@user).deliver_later(wait_until: 5.days.from_now)
使用全局ID
Rails的全局ID功能允许你给#perform
传递ActiveRecord 模型来作为参数,从而:
def perform(user_id)
user = User.find(user_id)
user.send_welcome_email!
end
可以被这样代替:
def perform(user)
user.send_welcome_email!
end
不幸的是,这意味着如果User
记录在作业排队之后但在 perform
调用之前这段时间内被删除了,异常处理将是不同的。使用规范的Sidekiq,你可以使用以下代码处理该问题:
def perform(user_id)
user = User.find_by(id: user_id)
if user
user.send_welcome_email!
else
# handle a deleted user record
end
end
使用Active Job,作为反序列化User
实例的一部分,perform(user)
将代替raise
来触发一个缺失记录异常。
你可以像下面这样解决此问题:
class MyJob < ActiveJob::Base
rescue_from ActiveJob::DeserializationError do |exception|
# handle a deleted user record
end
# ...
end
Job ID
Active Job 有自己的Job ID,Sidekiq不使用该ID。你可以使用provider_job_id
来得到Sidekiq的JID。
job = SomeJob.perform_later
jid = job.provider_job_id
性能
基准测试显示Active Job把作业推送到Redis要慢2-20倍,并且处理开销约为3倍(使用Rails 5.1.4 搭配 Sidekiq 5.1.1)。由于所有基准测试的性能可能会因版本而异,因此YMMV。
队列前缀
Active Job允许你配置队列的前缀。不要使用“环境特殊”的前缀。每个环境应该使用完全独立的Redis数据库,否则,你的所有环境将共享相同的重试和计划设置,这可能会发生混乱。
商业功能
如果你的Active Job试着使用一些Sidekiq Pro和Sidekiq商业版的功能,它可能被不可预料的打断。例如,在基础情况下,在批处理中创建Active Job是能行的,但是如果你在这些作业中使用Active Job的重试机制的话是会失败的。当有疑问时,不要将Active Job与Sidekiq native APIs结合使用。