Joe Half Face
Joe Half Face

Reputation: 2333

Can I put retry in rescue block without begin ... end?

I ran into a problem, when PG fails out of sync (well known problem)(example).

PG fails out of sync, sequence of id stops incrementing and raises ActiveRecord::RecordNotUnique error.

But all solutions proposed here (all I found) propose some manual solutions - either do some operations in console, either run custom rake task.

However, I find this unsatisfying for production: each times it happens, users get 500, while someone administrating server should operatively save the day. (And according to test data for some reason it possible will occur frequently in my case).

So I would like rather to patch ActiveRecord Base class to catch this specific error and rescue it.

I use this logic sometimes in controller:

class ApplicationController < ActionController::Base

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

However, here I don't need retry. Also, I would like to not to go deep in monkey patching, for example, without overriding Base create method.

So I was thinking of something like this:

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

But it most likely doesn't work, as I'm not sure if Rails/Ruby will understand what exactly it asked to retry.

Is there any solution?

P.S. Not related solution for overall problem of sequence which will work without manual command line commands and having unserved users are also appreciated.

Upvotes: 2

Views: 1812

Answers (1)

Adam Lassek
Adam Lassek

Reputation: 35515

To answer the question you're asking, no. rescue can only be used from within a begin..end block or method body.

begin
  bad_method
rescue SomeException
  retry
end

def some_method
  bad_method
rescue SomeException
  retry
end

rescue_from is just a framework helper method created because of how indirect the execution is in a controller.

To answer the question you're really asking, sure. You can override create_or_update with a 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

Upvotes: 3

Related Questions