How to fix Net::ReadTimeout in SOAP API using Savon Ruby gem?

Hi, my script works but due to some reason it is throwing Net::ReadTimeout error. I presume due to high number of connections to the API. Any way to delay timeout using Savon? Thanks.

wsdl = 'https://org.my.domain/webservices/myservice.asmx?WSDL'

# Open Client Webservice
client = Savon.client(wsdl: wsdl, ssl_verify_mode: :none, ssl_version: :TLSv1, convert_request_keys_to: :none)

# Connect to Webservice - Authenticate
response = client.call(:authenticate, message: { username: 'user', password: 'pwd', organization: 'org', domain: 'my.domain' })

Seems like you can set the read timeout Class: Savon::GlobalOptions — Documentation for savonrb/savon (master)

hi, thanks. Just wondering if there’s a ruby function or command that can output the counts in sec during timeout? I learned that open_timeout by default is 2s and read_timeout is 60s in savon 2. Thanks!

Not quite sure what you want to do here. When you run client.call(), your program blocks (waits) until the service responds or the read timeout occurs. If there was no read timeout set, it could block forever in some cases.

In the event of a timeout, the operating system wakes your process up after read_timeout seconds so it can throw the timeout exception. So in the timeout case the duration will always be the same as the read_timeout value, so we don’t need to measure it - we know what it is because we set it. So do you want to capture how long the service takes when it executes normally? i.e. capture the response times when it doesn’t time out? Or are you maybe looking for some kind of countdown timer that ticks down from read_timeout until the service either returns or is killed by the timeout?

hi @specious, sorry for the late response. Yes, I was thinking of a counter that can possibly output the timeout in seconds. I doubt that looping is an option unless the loop loops exactly per second. I have a max read_timeout of course but I thought maybe there’s a way to output the timeout value like that of an exit code.

The simplest thing is to capture the current time before you make the call. I’ve used a method that times out about 50% of the time to simulate your call.

def might_timeout
  duration = rand(1..10)
  if duration > 5
    sleep 5
    raise 'Timed out'
  end
  sleep duration
end

3.times do
  started = Time.now

  begin
    might_timeout
  rescue RuntimeError
    print 'Timed out: '
  end

  puts Time.now - started
end

which produced

1.00287
Timed out: 5.000988
2.002774

Does that help at all?

It looks cool! Yes, it does help. I’ll try it. Thanks a lot @specious