Как определить ошибку тайм-аута соединения из-за ошибки тайм-аута чтения в Ruby's Net :: HTTP - PullRequest
7 голосов
/ 13 апреля 2010

Мой вопрос связан с Как устранить проблемы с тайм-аутом (Ruby, Rails) .

Вот обычный способ спасти от таймаута:

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

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

Ответы [ 2 ]

11 голосов
/ 13 апреля 2010

Вот решение (после исправления Бена):

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 голосов
/ 12 июля 2016

Решение от Marc-André Lafortune остается лучшим, если вы не можете перейти на ruby ​​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).

РЕДАКТИРОВАТЬ: тест 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...