web-dev-qa-db-fra.com

Comment réessayer urllib2.request en cas d'échec?

Quand urllib2.request atteint le délai d'expiration, un urllib2.URLError l'exception est levée. Quelle est la méthode Pythonic pour réessayer d'établir une connexion?

30
iTayb

J'utiliserais un décorateur réessayer . Il y en a d'autres, mais celui-ci fonctionne plutôt bien. Voici comment vous pouvez l'utiliser:

@retry(urllib2.URLError, tries=4, delay=3, backoff=2)
def urlopen_with_retry():
    return urllib2.urlopen("http://example.com")

Cela réessayera la fonction si URLError est levé. Consultez le lien ci-dessus pour obtenir de la documentation sur les paramètres, mais en gros, il réessayera un maximum de 4 fois, avec un retard de coupure exponentiel doublant à chaque fois, par ex. 3 secondes, 6 secondes, 12 secondes.

58
jterrace

Il existe quelques bibliothèques spécialisées dans ce domaine.

L'un est backoff , qui est conçu avec une sensibilité particulièrement fonctionnelle. Les décorateurs reçoivent des callables arbitraires renvoyant des générateurs qui produisent des valeurs de retard successives. Une interruption exponentielle simple avec un temps de relance maximum de 32 secondes pourrait être définie comme:

@backoff.on_exception(backoff.expo,
                      urllib2.URLError,
                      max_value=32)
def url_open(url):
    return urllib2.urlopen("http://example.com")

Un autre est nouvelle tentative qui a des fonctionnalités très similaires mais une API où les paramètres de nouvelle tentative sont spécifiés au moyen d'arguments de mot clé prédéfinis.

6
bgreen-litl

Pour réessayer sur timeout, vous pouvez attraper l'exception comme @ Karl Barker suggéré dans le commentaire :

assert ntries >= 1
for _ in range(ntries):
    try:
        page = urlopen(request, timeout=timeout)
        break # success
    except URLError as err:
        if not isinstance(err.reason, socket.timeout):
           raise # propagate non-timeout errors
else: # all ntries failed 
    raise err # re-raise the last timeout error
# use page here
3
jfs