具有后台作业和ActiveRecord的common problem是在将所需模型提交到数据库之前将作业排队并执行的时间。
ActiveRecord模型有一个很好的after_commit
回调,可以用于特定的模型。
但是,假设您有一些涉及几种不同模型的业务逻辑,并且在单个模型中填充逻辑并不合适。因此,您编写了某种服务/命令对象来执行事务块中的逻辑:
例如,类似于:
class SomeServiceObject
def execute
thing = create_thing_in_a_tx
# this notification often fires before the above transaction commits.
notify_user(thing)
end
private
def create_thing_in_a_tx
ActiveRecord::Base.transaction do
a = ModelA.new(foo: 'bar')
b = ModelB.new(a_record: a, biz: 'baz')
#... various other logic that doesn't really belong in a model ...
ThingModel.create!(b_record: b)
end
end
def notify_user(thing)
EnqueueJob.process_asyc(thing.id)
end
end
在这种情况下,据我所知,您实际上无法访问方便的after_commit
回调。
我想在上面的示例中,您可以ThingModel
将after_commit
回调中的作业排入队列,但是然后您将SomeServiceObject
的责任分散到不同的ActiveRecord::Base.transaction
类,感觉错误。
鉴于上述所有情况,是否有任何合理的方法可以知道after_commit
阻止何时提交,而不诉诸任何特定模型的"=="
回调?
谢谢! :-D
(另见:How to force Rails ActiveRecord to commit a transaction flush)
答案 0 :(得分:1)
它比你想象的要简单。 ActiveRecord::Base.transaction
块完成后,事务已提交。
def create_thing_in_a_tx
begin
ActiveRecord::Base.transaction do
a = ModelA.new(foo: 'bar')
b = ModelB.new(a_record: a, biz: 'baz')
#... various other logic that doesn't really belong in a model ...
ThingModel.create!(b_record: b)
end
# The transaction COMMIT has happened. Do your after commit logic here.
rescue # any exception
# The transaction was aborted with a ROLLBACK.
# Your after commit logic above won't be executed.
end
end