【问题标题】:Handle TimeOut::Error with retry重试处理 TimeOut::Error
【发布时间】:2012-01-26 15:37:58
【问题描述】:

我有一个在 Heroku 上运行的应用程序,有时会报告 Timeout::Error(ActionView::Template::Error) “执行已过期”

这发生在整个网站上(即不在特定控制器中),所以我想创建一个函数来处理这两个错误,首先重试两次,然后将用户重定向到一个页面,该页面会告诉他们服务器正忙。

我目前的计划是在 ApplicationController 中使用以下内容:

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

  def rescue_from_timeout
    sleep 2
    retry 
  end

但这只会循环。我希望它在两次尝试后破裂。我该怎么做?

另外,如何处理 ActionView::Template::Error 的“执行过期”?我不想通过重试来拯救所有 ActionView::Template::Error,只有那些引发“执行已过期”的。

这就是我的例外所说的:

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

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

因此,我的问题是:如何通过首先重试两次然后抛出异常/重定向到错误页面来处理这两种类型的错误?

【问题讨论】:

  • 为什么会引发这个异常?您是否实现了某种长时间运行的任务,您的应用是否依赖于外部 Web 服务?

标签: ruby-on-rails timeout


【解决方案1】:

定义这个方法:

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

然后用这个调用:

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

你可以把它放在应用控制器的 around_filter 中,它是 Rails 应用中所有控制器的基类:

class ApplicationController < ActionController::Base

  around_filter :retry_on_timeout

  def retry_on_timeout
    retryable(:tries =>  10, :on => Timeout::Error) do
      yield
    end
  end
end

【讨论】:

  • 谢谢,道格拉斯。但是我不确定在哪里/如何使用调用代码。如果我想使用它以便它在整个网站上捕获此错误,我想我会在应用程序控制器中调用一些东西作为 before_filter 或其他东西。我是否需要用可重试功能包装每个控制器等?您能否详细说明我如何使用它来捕获整个网站(所有控制器/视图)的错误。
  • 我在 ApplicationController 中使用环绕过滤器编辑了答案。这适用于你吗?
  • 我无法测试它,只能让它在线几天看看它是否会删除这些错误消息,但它似乎正在工作。或者,有没有办法引发 TimeoutError 以便我可以测试它?
  • 您可以尝试添加此代码:raise TimeoutError(请在常量 Module::TimeoutError 之前添加模块)
  • sleep 2 是干什么用的?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-10
  • 2011-02-15
  • 2012-07-11
  • 2018-05-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多