【问题标题】:Issues When Rescuing ActiveRecord::RecordNotUnique拯救 ActiveRecord::RecordNotUnique 时的问题
【发布时间】:2016-03-29 23:07:31
【问题描述】:

我正在尝试构建一个表,该表将作为批量同步到第三方服务的队列。

以下方法不言自明;但需要明确的是,它的目的是在delayed_syncs 表中添加一个带有status: :queued 的新可更新对象(多态关系)。

对多态关系 + status (updatable_id, updatable_type, status) 存在唯一性约束,这应该会导致队列中已经存在 :queued status 的可更新对象在此处失败并落入救援块。

我看到的问题是,每当find_by 生成的SELECT 被触发时,整个方法都会失败并显示:

ActiveRecord::StatementInvalid

错误。

我在这方面发现的信息表明在失败的INSERT 之后会出现ROLLBACKRELEASE SAVEPOINT,但我不确定如何在这里完成。

上述方法:

def self.enqueue(updatable:, action:)
  DelayedSync.create(updatable: updatable, status: :queued, action: action)
rescue ActiveRecord::RecordNotUnique
  queued_update = DelayedSync.find_by(updatable: updatable, status: :queued, action: :sync_update)
  if action == :sync_delete && queued_update.present?
    queued_update.sync_delete!
  else
    Rails.logger.debug "#{updatable.class.name} #{updatable.id} already queued for sync, skipping."
  end
end

【问题讨论】:

  • 错误信息是什么?

标签: sql ruby-on-rails ruby postgresql activerecord


【解决方案1】:

您可以使用ActiveRecord 事务来确保全有或全无更新,而不是依赖逻辑异常处理。

像这样:

ActiveRecord::Base.transaction do
  DelayedSync.create!(updatable: updatable, status: :queued, action: action)
end

您仍然可以安全地使用rescue 来处理日志清理。

可以在here 找到对此有更多详细信息的文档。

【讨论】:

    【解决方案2】:

    经过进一步挖掘,我发现问题出在我如何从 after_save 回调中调用此方法。 Rails 在事务关闭之前调用after_saveafter_destroy 回调。使用 Postgres 无法挽救从此回调调用的 ActiveRecord::RecordNotUnique 错误并尝试执行更多查询,因为它会使整个事务无效。我的解决方案是转换到after_commit 回调,它提供与after_saveafter_destroy 相同的控制,带有on: [:create, :destroy] 参数,好处是事务之后执行(无效或not) 已关闭。

    这篇博文有点过时了,但底部附近的信息非常有用并且仍然适用:http://markdaggett.com/blog/2011/12/01/transactions-in-rails/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-04-24
      • 2023-04-08
      • 1970-01-01
      • 2011-02-06
      • 2015-02-15
      • 2013-06-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多