我的Rails应用程序似乎有竞争条件。在删除用户和依赖于它的所有相关模型时,用户有时会创建新的关联模型。如果我们删除大量内容,用户删除可能需要一段时间,因此这里存在竞争条件是有道理的。这最终会创建指向不存在的用户的模型。
我尝试通过创建UserDeletion模型来解决这个问题,该模型充当一种互斥锁。在开始删除用户之前,它将创建一个新的UserDeletion记录。当用户尝试创建新内容时,它会检查以确保关联的UserDeletion记录不存在。完成后,它会删除它。
但这并没有解决问题,所以我想知道其他人如何处理AR回调和竞争条件的类似问题。
答案 0 :(得分:-1)
首先,当关联的内容很多时,我们继续使用SQL DELETE
来代替Rails destroy
使用手动删除过程。 (虽然这对你来说可能不起作用,如果你不小心引入了很多回调依赖,它会在记录被破坏后做某事)
def custom_delete
self.class.transaction do
related_objects.delete_all
related_objects_2.delete_all
delete
end
end
如果你发现自己一直在写这个,你可以简单地将它包装在接受related_objects键列表的类方法中去删除。
class ActiveRecord::Base
class << self
def bulk_delete_related(*args)
define_method "custom_delete" do
ActiveRecord::Base.transaction do
args.each do |field|
send(field).delete_all
end
end
delete
end
end
end
end
class SomeModel < ActiverRecord::Base
bulk_delete :related_objects, :related_objects2, :related_object
end
我直接在ActiveRecord :: Base类中插入了类方法,但可能你最好将它提取到模块中。此外,这只能加快速度,但无法解决原始问题。
其次你可以引入FK约束(我们这样做是为了确保完整性,因为我们做了很多自定义SQL)。只要有链接对象,它就会以不会被删除的方式工作。虽然它可能不是你想要的。为了提高此解决方案的有效性您始终可以将用户删除委派给后台作业,该作业将重试删除用户,直到实际可以删除用户(没有丢弃新对象)
或者你也可以像我之前在某些情况下的工作那样做。如果删除用户更重要,而不是确定没有僵尸记录,请使用一些滑动过程来不时清理。
最后,事实是中间的某个地方 - 在删除用户之前对必须清理的关系应用约束,并且只依靠清扫程序删除不应该干扰用户删除的不太重要的关系。
问题并非微不足道,但在某种程度上它应该是可以解决的。