在Rails中使用Thread.new运行destroy_all或Thread.new来包装事务中的模型方法

时间:2014-09-23 03:26:58

标签: ruby-on-rails ruby-on-rails-4

我一直在寻找一种方法来安全地在模型的方法中运行delete_all,而不是招致网络服务器超时(例如30秒)。

让我们说场景如下:我可能有50K项目记录和150k相关ItemHistory记录。显然使用destroy_all(加载每个记录的实例并发送单个删除)并不是最佳的。你会如何解决这个问题?我也有delayed_job并尝试使用.delay方法但不相信它非常适合这个问题。所以,我开始关注Threads,但我想安全地使用它们。

场景#1销毁数十万条过期记录

Thread.new do
  Item.expired.find_each do |item|
    item.destroy_all # this will also destroy ItemHistory records
  end
  ActiveRecord::Base.connection.close
end

与前一个问题类似,在Thread中使用事务有什么缺陷(我想这是支持的)?

场景#2 - 在线程中使用交易

Thread.new do
    ActiveRecord::Base.transaction do   
      User.import(account_id)
      Item.import(account_id)
    end
    ActiveRecord::Base.connection.close
end

我需要考虑一些问题吗?

2 个答案:

答案 0 :(得分:2)

最好通过将删除移动到后台工作程序来解决。我建议看Sidekiq。

答案 1 :(得分:1)

你试过天真的延迟,就像在

中一样
Item.expired.delay.destroy_all

这不好,因为它将获取所有这些项目并在作业正文中序列化它们。这是一个庞大的文本。

你需要做的是一项专门的工作。像这样:

class PruneExpiredItems
  def perform
    Item.expired.destroy_all
  end
end

Delayed::Job.enqueue PruneExpiredItems.new
# or
PruneExpiredItems.new.delay.perform

此外,

你需要destroy_all吗?也就是说,你依靠它来调用你的回调(级联删除和诸如此类的东西)吗?如果没有,您可以尝试delete_all只向{db}发送DELETE FROM命令。效率更高。