【问题标题】:unable to catch ruby exception无法捕捉红宝石异常
【发布时间】:2012-12-14 12:28:26
【问题描述】:

具有以下长期运行的 rake 批处理:

class SyncStarredRepo
  include Mongoid::Document

  def self.update

    User.all.map do |user| 

      if user.email != "admin@gitwatcher.com"
        begin 
          conn = Faraday.new "https://api.github.com" 
          i = 1  
          begin   
            resp = conn.get "/users/#{user.nickname}/starred?page=#{i}"
            resp.body.each do |repo|
              attempts = 0
              begin 
                existing_repo = user.watchlists.where( html_url: "#{repo['html_url']}" ).batch_size(30)
                if existing_repo.exists?  
                  existing_repo.first.update_attributes!(
                      html_url: "#{repo['html_url']}",
                      description: "#{repo['description']}"
                  )
                else   
                  user.watchlists.create!(
                      html_url: "#{repo['html_url']}",
                      description: "#{repo['description']}"
                  )
                end

              rescue Moped::Errors::CursorNotFound => c
                attempts += 1
                puts "error message: #{c.message}"
                if attempts < 3
                  puts "Retrying... Attempt #: #{attempts.to_s}"
                  sleep(3)
                  retry 
                else 
                  puts "already retried 3 times, go to the next"
                  next
                end
              end

            end  
            i += 1 
          end until resp.body.empty? 

        rescue TypeError => e
          puts "message error (e.inspect): #{e.inspect}"
          puts "go to the next user"
          next    
        rescue  
          p $!, *$@
          next    
        end  
      end  

    end 
  end
end

我想捕获 Moped::Errors::CursorNotFound 异常,但它不起作用。

在 crontab 日志中我只收到这条消息:

rake aborted!
The operation: "GET MORE"
failed with error "cursor 2509315744412059250 not found"

然后批处理停止并退出,而我正在处理救援消息和下一个循环操作。

更新

我正在尝试通过这样做“扩展”设置为 StandardError 的可捕获异常:

      rescue
        p $!, *$@
        next
      end

... 以防万一,即使 CursorNotFound 继承自 MongoError,后者继承自 StandardError,如您所见 here .

更新

我刚刚更新了之前的简化代码,使用了 rake 使用的完整的 SyncStarredRepo 类,以防万一我在循环逻辑中遗漏了一些东西,开始/救援/结束等等...

更新

按照rake -t 打印的堆栈跟踪:

rake aborted!
The operation: "GET MORE"
failed with error "cursor 5781947091640256877 not found"
/var/www/gitwatcher/vendor/bundle/ruby/1.9.1/gems/moped-1.3.2/lib/moped/node.rb:210:in `get_more'
/var/www/gitwatcher/vendor/bundle/ruby/1.9.1/gems/moped-1.3.2/lib/moped/cursor.rb:44:in `get_more'
/var/www/gitwatcher/vendor/bundle/ruby/1.9.1/gems/moped-1.3.2/lib/moped/cursor.rb:29:in `each'
/var/www/gitwatcher/vendor/bundle/ruby/1.9.1/gems/moped-1.3.2/lib/moped/query.rb:77:in `each'
/var/www/gitwatcher/vendor/bundle/ruby/1.9.1/gems/moped-1.3.2/lib/moped/query.rb:77:in `each'
/var/www/gitwatcher/vendor/bundle/ruby/1.9.1/bundler/gems/mongoid-92cad16e9fbf/lib/mongoid/contextual/mongo.rb:133:in `block in each'
/var/www/gitwatcher/vendor/bundle/ruby/1.9.1/bundler/gems/mongoid-92cad16e9fbf/lib/mongoid/contextual/mongo.rb:605:in `selecting'
/var/www/gitwatcher/vendor/bundle/ruby/1.9.1/bundler/gems/mongoid-92cad16e9fbf/lib/mongoid/contextual/mongo.rb:132:in `each'
/var/www/gitwatcher/vendor/bundle/ruby/1.9.1/bundler/gems/mongoid-92cad16e9fbf/lib/mongoid/contextual.rb:18:in `each'
/var/www/gitwatcher/app/models/sync_starred_repo.rb:15:in `map'
/var/www/gitwatcher/app/models/sync_starred_repo.rb:15:in `update'
/var/www/gitwatcher/lib/tasks/scheduler.rake:9:in `block in <top (required)>'
/usr/local/rvm/gems/ruby-1.9.3-p194@rails-3.2.8/gems/rake-0.9.2.2/lib/rake/task.rb:205:in `call'
/usr/local/rvm/gems/ruby-1.9.3-p194@rails-3.2.8/gems/rake-0.9.2.2/lib/rake/task.rb:205:in `block in execute'
/usr/local/rvm/gems/ruby-1.9.3-p194@rails-3.2.8/gems/rake-0.9.2.2/lib/rake/task.rb:200:in `each'
/usr/local/rvm/gems/ruby-1.9.3-p194@rails-3.2.8/gems/rake-0.9.2.2/lib/rake/task.rb:200:in `execute'
/usr/local/rvm/gems/ruby-1.9.3-p194@rails-3.2.8/gems/rake-0.9.2.2/lib/rake/task.rb:158:in `block in invoke_with_call_chain'
/usr/local/rvm/rubies/ruby-1.9.3-p194/lib/ruby/1.9.1/monitor.rb:211:in `mon_synchronize'
/usr/local/rvm/gems/ruby-1.9.3-p194@rails-3.2.8/gems/rake-0.9.2.2/lib/rake/task.rb:151:in `invoke_with_call_chain'
/usr/local/rvm/gems/ruby-1.9.3-p194@rails-3.2.8/gems/rake-0.9.2.2/lib/rake/task.rb:144:in `invoke'
/usr/local/rvm/gems/ruby-1.9.3-p194@rails-3.2.8/gems/rake-0.9.2.2/lib/rake/application.rb:116:in `invoke_task'
/usr/local/rvm/gems/ruby-1.9.3-p194@rails-3.2.8/gems/rake-0.9.2.2/lib/rake/application.rb:94:in `block (2 levels) in top_level'
/usr/local/rvm/gems/ruby-1.9.3-p194@rails-3.2.8/gems/rake-0.9.2.2/lib/rake/application.rb:94:in `each'
/usr/local/rvm/gems/ruby-1.9.3-p194@rails-3.2.8/gems/rake-0.9.2.2/lib/rake/application.rb:94:in `block in top_level'
/usr/local/rvm/gems/ruby-1.9.3-p194@rails-3.2.8/gems/rake-0.9.2.2/lib/rake/application.rb:133:in `standard_exception_handling'
/usr/local/rvm/gems/ruby-1.9.3-p194@rails-3.2.8/gems/rake-0.9.2.2/lib/rake/application.rb:88:in `top_level'
/usr/local/rvm/gems/ruby-1.9.3-p194@rails-3.2.8/gems/rake-0.9.2.2/lib/rake/application.rb:66:in `block in run'
/usr/local/rvm/gems/ruby-1.9.3-p194@rails-3.2.8/gems/rake-0.9.2.2/lib/rake/application.rb:133:in `standard_exception_handling'
/usr/local/rvm/gems/ruby-1.9.3-p194@rails-3.2.8/gems/rake-0.9.2.2/lib/rake/application.rb:63:in `run'
/usr/local/rvm/gems/ruby-1.9.3-p194@rails-3.2.8/gems/rake-0.9.2.2/bin/rake:33:in `<top (required)>'
/usr/local/rvm/gems/ruby-1.9.3-p194@rails-3.2.8/bin/rake:23:in `load'
/usr/local/rvm/gems/ruby-1.9.3-p194@rails-3.2.8/bin/rake:23:in `<main>'
Tasks: TOP => update_starred_list_per_user

【问题讨论】:

  • 不是 100% 确定,但可能是因为异常是在第二个 begin 块内引发的吗?如果将救援移动到内部 begin 块内会发生什么?
  • 我正在尝试......但运行或多或少需要我们......我会尽快更新
  • @freakyDaz 没关系。如果没有与begin...end 关联的rescue,那么异常就会正常冒泡。
  • @Andrew Marshall ...事实上,它无论如何都不起作用
  • 你能把rake -t $YOUR_TASK打印的stacktrace贴出来吗?

标签: ruby exception exception-handling mongoid3 moped


【解决方案1】:

在User.all.map 期间引发了错误,因此您必须将begin..rescue 块包裹在整个语句周围。

基于初始信息的旧答案:

你是在你的循环之外进行救援,所以retry 并没有完全按照你的预期去做(另一方面,next 会引发 SyntaxError (1.9) 或 LocalJumpError (1.8 ))。事实上,rescue 内的 retry 只会导致 begin..rescue 块内的代码再次运行。

正确的代码应该是这样的:

attempts = 0
begin 
  i = 1 
  resp = conn.get "/users/#{user.nickname}/starred?page=#{i}"
  resp.body.each do |repo|
    begin
      existing_repo = user.watchlists.where( html_url: "#{repo['html_url']}" )
      if existing_repo.exists? 
        existing_repo.first.update_attributes!(
            html_url: "#{repo['html_url']}",
            description: "#{repo['description']}"
        )
      else 
        user.watchlists.create!(
            html_url: "#{repo['html_url']}",
            description: "#{repo['description']}"
        )
      end
    rescue Moped::Errors::CursorNotFound => c
      attempts += 1
      puts "error message: #{c.message}"
      if attempts < 3
        puts "Retrying... Attempt #: #{attempts.to_s}"
        sleep(3)
        retry 
      else 
        puts "already retried 3 times, go to the next"
        next
      end
    end
  end 
  i += 1
end until resp.body.empty?

【讨论】:

  • 你是对的,在 User.all.map 语句周围它捕获了异常
【解决方案2】:

虽然我没有仔细查看您的代码,但请注意,rescue 没有捕获所有异常。为此,您需要rescue Exception。

【讨论】:

  • 当然,我知道,但这不是一个好习惯(请参阅stackoverflow.com/questions/10048173/…)
  • 视情况而定。在很多情况下,无论如何捕获所有异常都是有意义的。
  • Ruby 向所有线程发送作为 SignalException 的 Interrupt 类,这样当进程收到 INT/Ctrl-C 信号时,所有线程都将展开并且进程将关闭。如果你抢救 Exception,你可能会捕捉到这个异常并忽略它,使你的线程和进程成为一个无法杀死的计算僵尸。你唯一的选择就是拔出你的 kill -9 霰弹枪瞄准头部。
  • 在某些情况下,您确实希望捕获此类异常并为它们提供您自己的自定义处理。在irb 中尝试 Ctrl-C。
  • :-) 好的,这不应该是这样,因为 CursorNotFound 继承自 MongoError,后者继承自 StandardError,如您在此处看到的:codeclimate.com/github/mongoid/moped/… ... 但我将给出无论如何都要尝试一下,以防万一:-)
猜你喜欢
  • 2017-06-21
  • 1970-01-01
  • 2012-03-02
  • 2017-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-18
  • 1970-01-01
相关资源
最近更新 更多