【问题标题】:Race conditions in AR destroy callbacksAR 中的竞争条件会破坏回调
【发布时间】:2013-10-15 14:27:26
【问题描述】:

我的 Rails 应用程序中似乎存在竞争条件。在删除用户和依赖于它的所有关联模型时,用户有时会创建新的关联模型。如果我们要删除大量内容,用户删除可能需要一段时间,因此这里存在竞争条件是有道理的。这最终会创建指向不存在的用户的模型。

我已尝试通过创建一个 UserDeletion 模型来解决此问题,该模型充当一种互斥锁。在开始删除用户之前,它将创建一个新的 UserDeletion 记录。当用户尝试创建新内容时,它会检查以确保关联的 UserDeletion 记录不存在。完成后,将其删除。

但这并没有解决问题,所以我想知道其他人是如何处理 AR 回调和竞争条件的类似问题的。

【问题讨论】:

    标签: ruby-on-rails callback race-condition


    【解决方案1】:

    首先,当关联的内容很多时,我们继续使用 SQL DELETE 而不是 Rails destroy 使用手动删除过程。 (虽然这可能对你不起作用,如果你不小心引入了很多回调依赖,在记录被销毁后会做一些事情)

    def custom_delete
      self.class.transaction do
        related_objects.delete_all
        related_objects_2.delete_all
        delete
      end
    end
    

    如果你发现自己一直在写这个,你可以简单地将它包装在接受要删除的相关对象键列表的类方法中。

    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)。只要有链接的对象,它将以不会删除用户的方式工作。虽然它可能不是你想要的。为了提高此解决方案的有效性您始终可以将用户删除委托给后台作业,该作业将重试删除用户,直到它实际上可以被删除(没有新对象放入)

    或者,在某些情况下,您可以像我之前的工作那样做相反的事情。如果删除用户比确保没有僵尸记录更重要,请不时使用一些滑动过程来清理。

    最后,事实在中间的某个地方 - 将约束应用于在删除用​​户之前肯定需要清理的关系,并仅依靠清扫器删除不应该干扰用户删除的不太重要的关系。

    问题不是小事,但应该可以在一定程度上解决。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-10-17
      • 2012-11-24
      • 2013-05-09
      • 1970-01-01
      • 2016-03-07
      • 2011-07-17
      • 2013-02-27
      相关资源
      最近更新 更多