2012-02-25 2 views
26

Когда urllib2.request достигает таймаута, исключение составляет urllib2.URLError. Что такое pythonic способ повторного установления соединения?Как повторить попытку urllib2.request при сбое?

+1

Этот вопрос должен ответить на ваш вопрос: http://stackoverflow.com/questions/2712524/handling-urllib2s-timeout-python –

+2

Я не спрашивал, как поймать искупление. Я хотел знать, есть ли путинский способ повторной попытки установить соединение. – iTayb

+0

Извините, я решил, что проблема заключается в обнаружении тайм-аута, а не в восстановлении соединения. Не могли бы вы вызвать urlopen() в блоке исключений? –

ответ

52

Я бы использовал декоратор retry. Есть и другие, но это работает очень хорошо. Вот как вы можете использовать его:

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

Это будет повторять функцию, если URLError поднята. Проверьте ссылку выше для документации по параметрам, но в основном она будет повторять максимум 4 раза, при этом экспоненциальная задержка отсрочки удваивается каждый раз, например. 3 секунды, 6 секунд, 12 секунд.

+1

Это действительно классный фрагмент. Вы знаете альтернативу, но как менеджер контекста? –

+0

Хмм, я думаю, вы могли бы, вероятно, переписать его в качестве менеджера контекста довольно легко, но у меня нет одного из них. – jterrace

+0

Это непросто сделать, поскольку нет простого способа захватить блок внутри оператора. Вам нужна глубокая интроспекция. –

3

Чтобы повторить попытку по истечении времени ожидания можно поймать исключение, как @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

Есть несколько библиотек там, которые специализируются на этом.

Первый - backoff, который разработан с особенно функциональной чувствительностью. Декораторам передаются произвольные вызывающие обратные генераторы, которые дают последовательные значения задержки. Простая экспоненциальная потеря мощность с максимальным временем повтора 32 секунд может быть определена как:

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

Другим retrying, который имеет очень похожую функциональность API, но где повторить параметры задаются посредством заранее определенных аргументов ключевых слов.

Смежные вопросы