Rescue in receive
Because when I write Ruby, I feel like I'm dragging it all up, so I prefer to write code in Ruby. Today I encountered a problem with Webdriver timeout, and the problem itself was due to the fact that I had no knowledge of webdriver and broken documents. First, let's simplify the question:
Driver = Selenium::webdriver.for:safari
Driver.navigate.to "Http://www.faraway.com"
wait = selenium::webdriver::wait.new (: timeout = +) # seconds
Wait.until {driver.find_element (: CSS, ' input[name= ' username "])}
Because the site is too far away, the speed is relatively slow, so timeout set a larger value: Timeout = 1000
Here we visit: Faraway This site, and then wait for the input box to enter the user name. The following error message was obtained:
/users/twer/.rvm/gems/[email protected]/gems/selenium-webdriver-2.42.0/lib/
selenium/webdriver/safari/server.rb:41:in' rescue in receive ': Timed off waiting for Safari to respond ( Selenium::webdriver::error::timeouterror)
From/users/twer/.rvm/gems/[email protected]/gems/selenium-webdriver-2.42.0/lib/selenium/webdriver/safari/ Server.rb:36:in ' Receive '
From/users/twer/.rvm/gems/[email protected]/gems/selenium-webdriver-2.42.0/lib/selenium/webdriver/safari/ Bridge.rb:68:in ' Raw_execute '
From/users/twer/.rvm/gems/[email protected]/gems/selenium-webdriver-2.42.0/lib/selenium/webdriver/remote/ Bridge.rb:612:in ' Execute '
From/users/twer/.rvm/gems/[email protected]/gems/selenium-webdriver-2.42.0/lib/selenium/webdriver/remote/ Bridge.rb:110:in ' Get '
From/users/twer/.rvm/gems/[email protected]/gems/selenium-webdriver-2.42.0/lib/selenium/webdriver/common/ Navigation.rb:14:in ' to '
from
faraway.rb:26: In ' <main> '
The place where I saw the error was called by the place where I wait. I thought I was not set: Timeout = 1000,wait wait time of 1000 seconds, why still not ah?
Monkey patch to save me.
I don't know, there are people blowing on it. Violent settlement. I found the file/selenium/webdriver/safari/server.rb marked in the red section above. (HTTPS://CODE.GOOGLE.COM/P/SELENIUM/SOURCE/BROWSE/RB/LIB/SELENIUM/WEBDRIVER/SAFARI/SERVER.RB)
Found the place where the error occurred 41 lines, is in the receive function:
def receive
@frame | | = Websocket::frame::incoming::server.new (: Version = @version)
Until Msg = @frame. Next
End_time = Time.now + @command_timeout
Begin
data = @ws. Read_nonblock (1)
Rescue Errno::ewouldblock, Errno::eagain
now = Time.now
If now >= end_time
raise Error::timeouterror, "timed out waiting for Safari to respond" #第41行
End
Io.select ([@ws], nil, nil, end_time-now)
Retry
End
@frame << Data
End
Puts "<<< #{msg}" if $DEBUG
Webdriver.json_load msg.to_s
End
As can be seen, is now >= End_time used to calculate whether to timeout, in front of the end_time is seen by the Time.now + @command_timeout obtained, and then into the begin/rescue/retry. Strange, my: timeout = 1000 Shouldn't it be work?
First Monkey Patch
I copied the above part of the code directly into my source file faraway.rb, made the following changes:
If now >= end_time
Puts @command_timeout
Raise Error::timeouterror, "timed out waiting for Safari to respond"
End
Found that @command_timeout is not 1000, but 60, that is, a minute.
A second monkey patch
Until Msg = @frame. Next
End_time = time.now + 1000
This forces @command_timeout to be set to 1000.
Running like this, no problem.
Explore
Although monkey patch can solve my problem of connecting faraway. However, as a quick test to get feedback is OK, it is still not very pleasant to use. So I began to read the source code, webdriver the code itself is quite simple. It's easy to read, but I don't know what to say. Minutes of discovering the problem is actually here:
Driver = Selenium::webdriver.for:safari,timeout:1000
Driver.navigate.to "Http://www.faraway.com"
The red part is not accounted for in the document, what does the timeout here mean? My wait is not already a timeout, how to driver in the creation of the need?
The reason is that there are two different timeout types. The timeout for wait indicates how long our driver will wait to know if this element appears. And the place where we went wrong is the timeout that driver receives the server's return information. Not sure yet?
In this case, at wait, driver will cycle through the code in the until to see if the situation in until is met. Each time the execution of the driver will send a request, this request actually has timeout time, so we first encountered the problem is not wait itself timeout. Instead, driver sends a command and receives it when it is timeout.
Clearly, it was faraway.com, who wanted to reproduce the problem. Change command timeout to 1 try
If I'm unfortunate again ...
I am the kind of person who is more fortunate than me. But the process of solving the problem is still very happy. Ruby is a dynamic language that can play monkey patches, which is helpful for locating problems quickly and solving problems. Happy.