Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handle TimeOut::Error with retry

I have an application running on Heroku that, on occasion, reports Timeout::Error and (ActionView::Template::Error) "execution expired".

This happens all over the website (i.e. not in a specific controller) so I would like to create a function that will handle these two errors, first by retrying two times and the redirect the user to a page that will tell them that the server is busy.

My current plan is to use the following in ApplicationController:

  rescue_from Timeout::Error, :with => :rescue_from_timeout

  def rescue_from_timeout
    sleep 2
    retry 
  end

but this will just loop and loop. I want it to break after two attempts. How can I do that?

Also, How can I handle ActionView::Template::Error for "execution expired"? I don't want to rescue all ActionView::Template::Error with retries, only the ones that provoke the "execution expired".

This is what my exception says:

[Exception] home#index (ActionView::Template::Error) "execution expired"

or

[Exception] calculations#result (ActionView::Template::Error) "Timeout::Error: execution expired

My question, thus: How can I handle these two types of errors by first retry twice and then throw an exception / redirect to error page?

like image 814
Christoffer Avatar asked Jan 26 '12 15:01

Christoffer


1 Answers

Define this method:

def retryable(options = {})
  opts = { :tries => 1, :on => Exception }.merge(options)

  retry_exception, retries = opts[:on], opts[:tries]

  begin
    return yield
  rescue retry_exception
    if (retries -= 1) > 0
      sleep 2
      retry 
    else
      raise
    end
  end
end

And call with this:

retryable(:tries => 10, :on => Timeout::Error) do
  your_code_here
end

You could put this in an around_filter in the application controller, that is the base class for all controllers in a rails application:

class ApplicationController < ActionController::Base

  around_filter :retry_on_timeout

  def retry_on_timeout
    retryable(:tries =>  10, :on => Timeout::Error) do
      yield
    end
  end
end
like image 99
Douglas Lise Avatar answered Nov 18 '22 00:11

Douglas Lise