2012-02-25 27 views
26

Po przekroczeniu limitu czasu , zgłaszany jest wyjątek urllib2.URLError. Jaki jest podpowiedziowy sposób ponownego nawiązania połączenia?Jak ponowić próbę urllib2.request w przypadku niepowodzenia?

+1

To pytanie powinno odpowiedzieć na twoje pytanie: http://stackoverflow.com/questions/2712524/handling-urllib2s-timeout-python –

+2

Nie pytałem, jak złapać wyrok. Chciałem wiedzieć, czy istnieje pythonic sposób, aby spróbować ponownie nawiązać połączenie. – iTayb

+0

Przepraszam, założyłem, że problem polegał na wykryciu limitu czasu, a nie ponownym ustanowieniu połączenia. Czy nie możesz wywołać urlopuen() w bloku wyjątku? –

Odpowiedz

52

Chciałbym użyć dekoratora retry. Są inne, ale ten działa całkiem nieźle. Oto w jaki sposób można go używać:

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

To będzie ponowić funkcję jeśli URLError jest podniesiony. Sprawdź powyższy link, aby uzyskać dokumentację parametrów, ale zasadniczo wznowi to maksymalnie 4-krotnie, z dwukrotnym podwojeniem wykładniczej zwłoki czasowej, np. 3 sekundy, 6 sekund, 12 sekund.

+1

To jest naprawdę fajny fragment. Czy znasz alternatywę, ale jako menedżer kontekstu? –

+0

Hmm, myślę, że prawdopodobnie mógłbyś przepisać go jako kontekstowy menedżer całkiem łatwo, ale nie mam żadnego offhandu. – jterrace

+0

Nie jest to łatwe, ponieważ nie ma łatwego sposobu przechwycenia bloku wewnątrz instrukcji with. Potrzebujesz głębokiej introspekcji. –

3

Aby ponowić po przekroczeniu tego limitu można złapać wyjątek jako @Karl Barker suggested in the comment:

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 
4

Istnieje kilka bibliotek tam, które specjalizują się w tym.

Jedną z nich jest backoff, która została zaprojektowana ze szczególnie funkcjonalną wrażliwością. Dekoratory są przekazywane przez arbitralne generatory zwrotne, które generują kolejne wartości opóźnień. Prosty wykładniczy ograniczania maksymalnej czasu ponawiania 32 sekund, może być zdefiniowane jako:

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

Innym jest retrying który ma bardzo podobną funkcjonalność, lecz API, gdzie ponownie parametry są określone za pomocą predefiniowanych argumentach kluczowe.

Powiązane problemy