2010-04-12 2 views
7

Мой вопрос связан с How to rescue timeout issues (Ruby, Rails).Как сообщить ошибку таймаута соединения из ошибки таймаута чтения в Ruby's Net :: HTTP

Вот простой способ, чтобы спасти от тайма-аута:

def action 
    # Post using Net::HTTP 
rescue Timeout::Error => e 
    # Do something 
end 

я хотел бы определить, если исключение было поднято при попытке подключения к хосту, или если он был поднят при попытке читает с хоста. Это возможно?

ответ

11

Вот решение (после того, как исправить Бен): решение

require "net/http" 
http = Net::HTTP.new("example.com") 
http.open_timeout = 2 
http.read_timeout = 3 
begin 
    http.start 
    begin 
    http.request_get("/whatever?") do |res| 
     res.read_body 
    end 
    rescue Timeout::Error 
    puts "Timeout due to reading" 
    end 
rescue Timeout::Error 
    puts "Timeout due to connecting" 
end 
+0

Марк, я действительно хочу, чтобы это было правдой, но это не работает для меня , Я думаю, что это потому, что 'http.request_get' создает и использует новый экземпляр« Net :: HTTP », который не наследует переменные таймаута. –

+0

Я беру это обратно, он не создает новый экземпляр «Net: HTTP». Тем не менее, кажется, что тайм-аут составляет около 30 секунд независимо от того, что я установил для открытия и чтения таймаутов. –

+0

open_timeout работает для меня, на обоих рубинах 1.8.7 и 1.9.2 dev. Трудно протестировать read_timeout, и это может быть прочитано в блоке, вы должны проверить код. Тем не менее, если вы поместите оба значения в 0,1, это должно быть слишком быстро, нет? В любом случае, мой ответ по-прежнему является правильным способом отличить то, что вызвало таймаут! –

0

Марк-Андре Lafortune по-прежнему лучше всего, если вы не можете обновить до рубинового 2.x.

Начиная с версии 2.x, подкласс Timeout::Error будет увеличен в зависимости от времени ожидания был вызван:

  • Net::OpenTimeout
  • Net::ReadTimeout

Однако read_timeout поведение странно на 2 .x, потому что он, кажется, удваивает значение, которое вы установили.

Вот тест для обоих тайм-аутов (проверен на 1.8.7, 1.9.3, 2.1.2, 2.2.4).

EDIT: тест open_timeout работает на Mac, но в Linux клиент получает сообщение об ошибке «соединение отказался».

require "net/http" 
require "socket" 

SERVER_HOST = '127.0.0.1' 
SERVER_PORT = 9999 

def main 
    puts 'with_nonlistening_server' 
    with_nonlistening_server do 
    make_request 
    end 

    puts 
    puts 'with_listening_server' 
    with_listening_server do 
    make_request 
    end 
end 

def with_listening_server 
    # This automatically starts listening 
    serv = TCPServer.new(SERVER_HOST, SERVER_PORT) 
    begin 
    yield 
    ensure 
    serv.close 
    end 
end 

def with_nonlistening_server 
    raw_serv = Socket.new Socket::AF_INET, Socket::SOCK_STREAM, 0 
    addr  = Socket.pack_sockaddr_in SERVER_PORT, SERVER_HOST 

    # Bind, but don't listen 
    raw_serv.bind addr 
    begin 
    yield 
    ensure 
    raw_serv.close 
    end 
end 

def make_request 
    http = Net::HTTP.new(SERVER_HOST, SERVER_PORT) 
    http.open_timeout = 1 
    http.read_timeout = 1 # seems to be doubled on ruby 2.x 
    start_tm = Time.now 
    begin 
    http.start 
    begin 
     http.get('/') 
    rescue Timeout::Error => err 
     puts "Read timeout: #{err.inspect}" 
    end 
    rescue Timeout::Error => err 
    puts "Open timeout: #{err.inspect}" 
    end 
    end_tm = Time.now 
    puts "Duration (sec): #{end_tm - start_tm}" 
end 

if __FILE__ == $PROGRAM_NAME 
    main 
end 

Пример вывода на 1.9.3:

with_nonlistening_server 
Open timeout: #<Timeout::Error: execution expired> 
Duration (sec): 1.002477 

with_listening_server 
Read timeout: #<Timeout::Error: Timeout::Error> 
Duration (sec): 1.00599 

Пример вывода на 2.1.2:

with_nonlistening_server 
Open timeout: #<Net::OpenTimeout: execution expired> 
Duration (sec): 1.005923 

with_listening_server 
Read timeout: #<Net::ReadTimeout: Net::ReadTimeout> 
Duration (sec): 2.009582 
Смежные вопросы