Ruby 2.3 - Добавяне на грешка при изчакване и известие към net:http заявка

Имам работеща система за генериране на грешки и изпращането им за използване от Active Admin.

Например в Active admin, за конкретна страница от нашата CMS, страницата може да изпълни:

url_must_be_accessible("http://www.exmaple.com", field_url_partner, "URL for the partner")

И това използва кода по-долу, за да изпрати до Active Admin Editor различен тип известия за грешки:

module UrlHttpResponseHelper

  def url_must_be_accessible(url, target_field, field_name)      
    if url
      url_response_code = get_url_http_response(url).code.to_i
      case url_response_code
      when -1                                                         
        # DNS issue; website does not exist; 
        errors.add(target_field,
          "#{field_name}: DNS Problem -> #{url} website does not exist")
      when 200
        return 
      when 304
         return
      else
        errors.add(target_field,
          "#{field_name}: #{url} sends #{url_response_code} response code")
      end
    end
  end

  def get_url_http_response(url)  
    uri = URI.parse(URI.encode(url))
    request = Net::HTTP.get_response(uri)
    return request
  rescue Errno::ECONNREFUSED, SocketError => e
    OpenStruct.new(code: -1)
  end

end

В локален режим това работи страхотно! Но в производството ние сме на Heroku и когато заявка pn Heroku надхвърли 30 секунди, като например, ако опитате тази връзка "http://www.exmaple.com", приложението се срива с "Грешка H12".

Бих искал да добавя към кода по-горе две неща - изчаквания: мисля, че имам нужда както от read_timeout, така и от open_timeout и че read_timeout + open_timeout трябва да бъде ‹ до 30 секунди, с нека вземем малко сигурност, по-добре ‹ 25 секунди

  • ако заявката все още "тече" след 25 секунди, тогава избягвайте достигането на 30 секунди, като се откажете/изпуснете заявката

  • и хванете това „изпуснахме заявката умишлено поради риск от изчакване“, като изпратите известие до потребителя. Бих искал да използвам текущата си система с нещо подобно на:

     rescue Errno::ECONNREFUSED, SocketError => e
        OpenStruct.new(code: -7) # = some random number
      end
    
    case url_response_code
    when -7
      errors.add(target_field,
              "#{field_name}: We tried to reach #{url} but this takes too long and risks crashing the app. please check the url and try again.")
    

Как мога да създам код като -1, но друг, за да спася това "изчакване"/"прекратяване на опита за заявка", което аз самият налагам.

Опитах, но нищо не работи. Не успявам да създам кода за улавяне и да премахна тази заявка, ако достигне 25 секунди...


person Mathieu    schedule 02.02.2018    source източник
comment
Опитахте ли да обвиете своя get_url_http_response(url) с блок Timeout.timeout { }`?   -  person nattfodd    schedule 05.02.2018
comment
не, не знаех за този метод! наистина изглежда много подходящо за моите нужди. ще го провери и ще види как да го използва. Също така ще трябва да уловя времето за изчакване на fatc, което кара заявката да отпадне, за да изпратя известие с текущата ми система (вижте въпроса)   -  person Mathieu    schedule 05.02.2018


Отговори (1)


Това не е много красиво решение (вижте: https://medium.com/@adamhooper/in-ruby-dont-use-timeout-77d9d4e5a001), но вярвам, че все още можете да го използвате тук, защото имате само едно нещо, което се случва вътре, обратно на примера във връзката, където множество действия може да причини неочевидно поведение:

def get_url_http_response(url)
  uri = URI.parse(URI.encode(url))
  request = Timeout.timeout(25) { Net::HTTP.get_response(uri) }
  return request
rescue Errno::ECONNREFUSED, SocketError => e
  OpenStruct.new(code: -1)
rescue Timeout::Error
  # return here anything you want
end
person nattfodd    schedule 05.02.2018
comment
хехе също се натъкнах на тази публикация преди 2 минути:) и те казват в коментарите, че дори ако избрах get_response read_timeout или write_timeout параметри, ти пак ще използвам във фонов режим Timeout Обърнете внимание, че Net::HTTP все още използва timeout за open_timeout, както се вижда в github.com/ruby/rub... ... поне read_timeout е внедрен по-добре сега - person Mathieu; 05.02.2018
comment
проработи! благодаря, ще разпределя точки след 22 часа, тъй като дотогава е блокиран от SO - person Mathieu; 05.02.2018