2016-09-24 64 views
1

使用Net :: HTTP,我定期發現下面的代碼從StandardError以「執行過期」消息解救,儘管Web服務器從訪問的URL記錄日誌顯示相應的響應很快發送。當Web服務器日誌顯示的響應時間超過5秒鐘時,我通常會看到Timeout :: Error代碼挽救。Ruby Net :: HTTP執行過期

什麼情況下會導致下面的代碼從StandardError的搶救與「執行過期」的,而不是從超時::錯誤拯救?

這個代碼運行在一個相對古老的Ruby 1.9.3上的多線程程序中,在一個不支持Ruby新版本的平臺上。儘管該程序是多線程的,但所顯示的代碼只能在單個線程上運行。

begin 
    connection = Net::HTTP.new(uri.host, uri.port) 
    connection.open_timeout = 5 
    connection.read_timeout = 5 
    connection.start do |http| 
    request = Net::HTTP::Post.new("/reader_events") 
    request.body = body 
    response = http.request(request) 
    end 
rescue StandardError => std_error 
    log "error sending event to server: #{std_error}" 
rescue Timeout::Error => error 
    log "timeout sending event to server" 
end 
+1

試着把你的'救援超時::錯誤'塊放在另一個救援塊之前。在Ruby中,大多數異常類都繼承自StandardError,所以如果Timeout :: Error也不會讓我感到意外。如果是這樣的話,那麼錯誤將是一種StandardError和一種Timeout :: Error。第一個匹配的「救援」處理程序獲勝。 –

+0

@HenrikN好的。打印'Timeout :: Error.ancestors'表明它確實從'StandardError'繼承。 – Casper

回答

2

這是因爲rescue的工作原理。看看Exception課程的文檔頁面。基本上你可以創建一個單一的一個繼承了許多例外,並使用救援與父類處理所有的人:

begin 
    ... 
rescue Exception => exception 
    ... 
end 

此代碼將拯救所有類型的異常爲Exception的是根(其他例外,從繼承它)。在你的情況從RuntimeErrorTimeout::Error繼承從StandardError繼承:

Timeout::Error.ancestors 
    => [Timeout::Error, RuntimeError, StandardError, Exception, Object, PP::ObjectMixin, Kernel, BasicObject] 

其結果是一種Exception

Timeout::Error.new.is_a?(StandardError) 
    => true 

你的情況的另一件事是,解釋器將檢查從每rescue聲明從上到下。這意味着首先它將檢查exception是否爲StandardError類型,隨後它將移動到以下rescue塊。你應該總是列出rescue塊從最具體到最一般的。

更改rescue塊的順序來修復代碼。

+0

啊,簡單的回答。謝謝! – davidgyoung