'Python: How to try again when experiencing a timeout

I have a Python program that connects to a server to send it some commands, but occasionally I get this error:

TimeoutError: [WinError 10060] A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond

In previous situations like this, I would use something like this:

try:
            Do something
        except KeyError:
            do something else

Could I do the same thing in this same situation? I.e.,

try:
                Do something
            except TimeoutError:
               Do something again

And if so, what would I do after the except TimeoutError? Would I just do the same command again?



Solution 1:[1]

Could I do the same thing in this same situtation

Yes! You can use try/except for any exception, and TimeoutError is nothing special.

and if so what would I do after the except TimeoutError? would I just do the same command again?

If you only want to retry once, and let a second timeout count as a real error, yes:

try:
    do something
except TimeoutError:
    do something

(If "do something" is more than a simple statement, you probably want to factor out the code so you don't repeat yourself.)

However, if you want to retry multiple times, you probably want a loop:

for _ in range(max_retries):
    try:
        do something
        break
    except TimeoutError:
        pass

You may want to add an else clause to the for to distinguish the two cases (succeeded, and did a break, vs. never succeeded and just ran out of tries).


Since the idea here is usually to deal with possibly-transient errors, there are additional things you might want to add, such as:

  • Re-raising the error, or raising a different one, after max_retries.
  • Logging at progressively higher levels (e.g., a debug message for a single failure, but a warning for `max_retries).
  • Retrying with exponential backoff (wait 1 second, then 2, 4, 8, …).
  • Pushing the URL to the end of the work queue instead of retrying immediately. You can use (URL, retry_count) pairs if you also want max_retries logic, (URL, timestamp) pairs if you also want exponential backoff, or both if you want both. (Of course this only works if you don't care about the order of responses, or can reorder them at the end.)
  • Different rules for different exceptions (e.g., 500, 502, 503, and 504 errors can all be caused by overload on a server or proxy, but the best retry logic may be different—and the best heuristics for 2018 may be different from 2010 or 2025).

For complicated combinations, a retry decorator, like the one linked in jterrace's helpful answer, is a great way to wrap up the behavior.

Solution 2:[2]

You can catch the TimeoutError like you mentioned:

import socket
import sys
try:
  dosomething()
except socket.TimeoutError:
  print >> sys.stderr, 'Retrying after TimeoutError'
  dosomething()

You could also use the retry decorator pattern on a function:

@retry(socket.TimeoutError)
def dosomething():
    # code that causes a TimeoutError
    ...

Solution 3:[3]

def f():
    pass #insert code here

To repeat once after the error:

try:
    f()
except TimeoutError:
    f()

Or to loop until success:

while True:
    try:
        f()
        break
    except TimeoutError:
        pass

Or with a limited number:

attempts = 3
while attempts:
    try:
        f()
        break
    except TimeoutError:
        attempts -= 1

Solution 4:[4]

Please run each example. They are ready!

Example 1

import sys

try:
    incorrect.syntaxThatIJustMadeUP()
except:
    print((sys.exc_info()[0])) #Now you know what to except and CATCH
else:
    print("You will never see this message")

Example 2

import sys

try:
    incorrect.syntaxThatIJustMadeUP()
except NameError:
    print("There is a problem with your SYNTAX, Dude!")
except:
    print((sys.exc_info()[0])) # In case another uncontrollable network problem occurs, User rages-Snaps IJ45
else:
    print("You will never see this message unless TRY succeeds")
    print("Why not put this try in a loop?")

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 jterrace
Solution 3 abarnert
Solution 4 Peter Mortensen