有了delayed_job
,我可以做这样的简单操作:
@foo.delay.increment!(:myfield)
是否可以对 Rails 的新 ActiveJob 做同样的事情?(无需创建一大堆执行这些小操作的作业类)
有了delayed_job
,我可以做这样的简单操作:
@foo.delay.increment!(:myfield)
是否可以对 Rails 的新 ActiveJob 做同样的事情?(无需创建一大堆执行这些小操作的作业类)
据我所知,目前不支持此功能。您可以使用接受模型或实例、要执行的方法和参数列表的自定义代理作业轻松模拟此功能。
但是,出于代码测试和可维护性的考虑,这种快捷方式并不是一个好方法。为您想要排队的所有内容制定特定的工作会更有效(即使您需要编写更多代码)。它迫使您更多地考虑应用程序的设计。
ActiveJob只是各种后台作业处理器之上的抽象,因此许多功能取决于您实际使用的提供者。但我会尽量不依赖任何后端。
通常,作业提供者由持久性机制和运行器组成。卸载作业时,您以某种方式将其写入持久性机制,然后其中一个运行者检索它并运行它。所以问题是:您能否以一种与您需要的任何操作兼容的格式来表达您的工作数据?
让我们定义什么是工作定义。例如,它可以是单个方法调用。假设这种语法:
Model.find(42).delay.foo(1, 2)
我们可以使用以下格式:
{
class: 'Model',
id: '42', # whatever
method: 'foo',
args: [
1, 2
]
}
现在我们如何从给定的调用构建这样的哈希并将其排入作业队列?
首先,看起来,我们需要定义一个类method_missing
来捕获被调用的方法名:
class JobMacro
attr_accessor :data
def initialize(record = nil)
self.data = {}
if record.present?
self.data[:class] = record.class.to_s
self.data[:id] = record.id
end
end
def method_missing(action, *args)
self.data[:method] = action.to_s
self.data[:args] = args
GenericJob.perform_later(data)
end
end
作业本身必须像这样重建该表达式:
data[:class].constantize.find(data[:id]).public_send(data[:method], *data[:args])
当然,您必须delay
在模型上定义宏。最好将其分解为一个模块,因为定义非常通用:
def delay
JobMacro.new(self)
end
它确实有一些限制:
ruby2ruby
gem 做到这一点)。依靠作业提供者正确序列化参数,如果失败,请使用您自己的代码帮助它。例如,que
在内部使用 JSON,所以无论在 JSON 中如何工作,都可以在que
. 例如,符号不会。一开始事情会以惊人的方式破裂。
因此,请确保在开始之前设置您的调试工具。
我写了一个 gem 可以帮助你解决这个问题 https://github.com/cristianbica/activejob-perform_later。但是请注意,我相信在您的代码周围有可能在工作人员中执行的方法是灾难的完美秘诀,没有小心处理:)