在超时的情况下向Watir添加重试机制

时间:2017-05-12 17:36:16

标签: ruby watir

我使用Ruby和Watir gem开发了一系列脚本。那些是菠菜包裹的,但这就是我要问的问题。

这些脚本的目的是进行一些功能点检查或简单地减轻一些非常重复的任务。

他们已经运行了一段时间,但最近,由于Chromedriver / Geckodriver(试过两种浏览器)和脚本之间的超时,我开始看到很多失败。当然,我可以简单地重启脚本,但当成功率低于70%时,它真的开始加剧。

我最终要做的就是把我所有的呼叫都包含在一个带有开始的Proc中的Watir中,救援会在超时的情况下重试。

这很丑陋并且违反了很多规则我几乎不得不诉诸这个解决方案,但至少使用这个我的脚本现在正在完成。

以下是我如何解决这个问题:

# takes a proc and wraps it around a series of rescue
def execute_block_and_rety_if_needed
  yield
rescue Net::ReadTimeout
  puts 'Read Timeout detected, retrying operation'
  retry
rescue Net::HTTPRequestTimeOut
  puts 'Http Request Timeout detected, retrying operation'
  retry
rescue Errno::ETIMEDOUT
  puts 'Errno::ETIMEDOUT detected, retrying operation'
  retry
end

示例用法如下所示:

execute_block_and_rety_if_needed { @browser.link(name: 'OK').wait_until_present.click } # click the 'OK' button

正如您所看到的,这显然违反了DRY原则,因为我需要每次都调用此过程。

我的问题是:如何将其作为Watir的模块/功能移动,以便自动拾取它。 (理想情况下,我会添加最大重试次数以防止无限循环)。

版本信息:   - Chromedriver => 2.29.461585   - GeckoDriver => 0.16.1   - Firefox => ESR 52   - Chrome => 58   - Watir => 6.2.1

就DRY评论而言,我提到了这样一个事实:我必须用proc处理所有Watir调用,对不起,如果这还不清楚。

execute_block_and_rety_if_needed { @browser.link(name: 'User').wait_until_present.click } # click the 'Edit' button 
execute_block_and_rety_if_needed { @browser.link(name: 'Cancel').wait_until_present.click } # click the 'Cancel' button 
execute_block_and_rety_if_needed { @browser.link(name: 'OK').wait_until_present.click } # click the 'OK' button

如果我想使用重试机制,上面只是一个例子。

2 个答案:

答案 0 :(得分:1)

你不应该为此使用一个块。您可以实现一个类似于:

的方法
def ensure_click(element, retries = 3)
  @retries ||= retries
  element.click
rescue Net::ReadTimeout, Net::HTTPRequestTimeOut, Errno::ETIMEDOUT => ex
  raise unless @retries > 0
  @retries = @retries - 1
  puts "#{ex.class} detected, retrying"
  retry
end

...
ensure_click(@browser.link(name: 'User'))
...

话虽如此,这些例外通常不是驱动程序错误,而是某种网络问题。这不正常。

答案 1 :(得分:1)

鉴于您要重试发送到浏览器的每个命令,您可能需要考虑在底层Selenium-WebDriver而不是Watir中解决问题。 Watir命令被发送到Selenium-WebDriver,后者又将它们发送到浏览器/驱动程序。

每个命令(或至少大多数)当前通过Selenium::WebDriver::Remote::Http:Default#request发送。您可以修补方法以将其包装在重试中。您的点击不仅会重试超时,而且每个其他命令都会重试 - 例如导航,设置字段,获取值等。

# Patch to retry timeouts during requests
require 'watir'
module Selenium
  module WebDriver
    module Remote
      module Http
        module DefaultExt
          def request(*args)
            tries ||= 3
            super
          rescue Net::ReadTimeout, Net::HTTPRequestTimeOut, Errno::ETIMEDOUT => ex
            puts "#{ex.class} detected, retrying operation"
            (tries -= 1).zero? ? raise : retry            
          end
        end
      end
    end
  end
end
Selenium::WebDriver::Remote::Http::Default.prepend(Selenium::WebDriver::Remote::Http::DefaultExt)

# Then you can use Watir as usual
browser = Watir::Browser.new :chrome   # this will retry timeouts
browser.goto('http://www.example.com') # this will also retry timeouts
browser.link.click                     # this will also retry timeouts