Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Catching timeout errors with ruby mechanize

Tags:

ruby

mechanize

I have a mechanize function to log me out of a site but on very rare occasions it times me out. The function involves going to a specific page, and then clicking on a logout button. On the occasional that mechanize suffers a timeout when either going to the logout page or clicking the logout button the code crashes. So I put in a small rescue and it seems to be working as seen below the first piece of code.

def logmeout(agent)
  page = agent.get('http://www.example.com/')
  agent.click(page.link_with(:text => /Log Out/i))
end      

Logmeout with rescue:

def logmeout(agent)
  begin
  page = agent.get('http://www.example.com/')
  agent.click(page.link_with(:text => /Log Out/i))
  rescue Timeout::Error 
    puts "Timeout!"
    retry
  end
end

Assuming I understand rescue correctly, it will do both actions over even if just the clicking timed out, so in the effort to be efficient I am was wondering if I could use a proc in this situation and pass it a code block. Would something like this work:

def trythreetimes
  tries = 0
  begin
  yield
  rescue
    tries += 1
    puts "Trying again!"
    retry if tries <= 3
  end
end

def logmeout(agent)
  trythreetimes {page = agent.get('http://www.example.com/')}
  trythreetimes {agent.click(page.link_with(:text => /Log Out/i))}
end

Note in my trythreetimes function I left it as generic rescue so the function would be more re-usable.

Thanks so much for any help anyone can provide, I realize there are a couple different questions in here but they are all things I am trying to learn!

like image 685
Sean Avatar asked Sep 15 '11 04:09

Sean


1 Answers

Instead of retrying some timeouts on some mechanize requests I think you'd better set Mechanize::HTTP::Agent::read_timeout attribute to a reasonable amount of seconds like 2 or 5, anyway one that prevent timeouts errors for this request.

Then, it seem's that your log out procedure only required access to a simple HTTP GET request. I mean there is no form to fill in so no HTTP POST request. So if I were you, I would prefere inspected the page source code (Ctrl+U with Firefox or Chrome) in order to identify the link which is reached by your agent.click(page.link_with(:text => /Log Out/i)) It should be faster because these type of pages are usually blank and Mechanize will not have to load a full html web page in memory.

Here is the code I would prefer use :

def logmeout(agent)
  begin
  agent.read_timeout=2  #set the agent time out
  page = agent.get('http://www.example.com/logout_url.php')
  agent.history.pop()   #delete this request in the history
  rescue Timeout::Error 
    puts "Timeout!"
    puts "read_timeout attribute is set to #{agent.read_timeout}s" if !agent.read_timeout.nil?
    #retry      #retry is no more needed
  end
end

but you can use your retry function too :

def trythreetimes
  tries = 0
  begin
  yield
  rescue Exception => e  
  tries += 1
  puts "Error: #{e.message}"
  puts "Trying again!" if tries <= 3
  retry if tries <= 3
  puts "No more attempt!"
  end
end

def logmeout(agent)
  trythreetimes do
  agent.read_timeout=2  #set the agent time out
  page = agent.get('http://www.example.com/logout_url.php')
  agent.history.pop()       #delete this request in the history
  end
end

hope it helps ! ;-)

like image 147
cz3ch Avatar answered Oct 18 '22 23:10

cz3ch