我使用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
如果我想使用重试机制,上面只是一个例子。
答案 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