我可以在没有开始...结束的情况下重新进入救援区吗?

时间:2016-04-17 18:48:26

标签: ruby-on-rails postgresql activerecord

我遇到了一个问题,当PG失败不同步时(众所周知的问题)(IntelliJ documentation)。

PG失败不同步,id序列停止递增并引发ActiveRecord::RecordNotUnique错误。

但是这里提出的所有解决方案(我发现的所有解决方案)都提出了一些手动解决方案 - 要么在控制台中执行某些操作,要么运行自定义rake任务。

然而,我发现这对于制作来说不满意:每次发生,用户都会得到500,而管理服务器的人应该可以节省一天。 (根据测试数据由于某种原因,在我的情况下可能经常发生)。

所以我想修补ActiveRecord Base类以捕获此特定错误并将其解救。

我有时在控制器中使用这个逻辑:

class ApplicationController < ActionController::Base

  rescue_from ActionController::ParameterMissing, ActiveRecord::RecordNotFound do |e|
     # some logic here
    end
  end

然而,在这里我不需要重试。另外,我想不要深入猴子修补,例如,不要覆盖Base创建方法。

所以我在考虑这样的事情:

module ActiveRecord
   class Base


       rescue ActiveRecord::RecordNotUnique => e
         if e.message.include? '_pkey' 
           table =e.message.match(//) #regex to define table
           ActiveRecord::Base.connection.reset_pk_sequence!(table)
           retry
         else
           raise
         end
       end
     end

但它很可能不起作用,因为我不确定Rails / Ruby是否会理解它要求重试的内容。

有没有解决方案?

P.S。对于没有手动命令行命令和没有非服务用户的序列整体问题的相关解决方案也不受欢迎。

1 个答案:

答案 0 :(得分:1)

回答你问的问题,不。 rescue只能在begin..end块或方法正文中使用。

begin
  bad_method
rescue SomeException
  retry
end

def some_method
  bad_method
rescue SomeException
  retry
end

rescue_from只是一个框架帮助器方法,因为执行在控制器中是间接的。

要回答这个问题,请确定 。您可以使用create_or_update / rescue覆盖retry

module NonUniquePkeyRecovery
  def create_or_update(*)
    super
  rescue ActiveRecord::RecordNotUnique => e
    raise unless e.message.include? '_pkey'
    self.class.connection.reset_pk_sequence!(self.class.table_name)
    retry
  end
end

ActiveSupport.on_load(:active_record) do
  include NonUniquePkeyRecovery
end