1

Python异常重试解决方案

 2 years ago
source link: https://www.biaodianfu.com/python-error-retry.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

术→技巧, 研发

Python异常重试解决方案

钱魏Way · 2020-10-14 · 965 次浏览

数据抓取时,经常遇到由于网络问题导致的程序异常,一开始的做法只是记录了错误内容,并对错误内容再进行后期处理。这里整理了一些更好的异常重试方法或机制。

初始版本

def crawl_page(url):
def log_error(url):
url = ""
crawl_page(url)
except:
log_error(url)
def crawl_page(url):
    pass

def log_error(url):
    pass

url = ""
try:
   crawl_page(url)
except:
    log_error(url)

改进版本(增加了重试次数):

attempts = 0
success = False
while attempts < 3 and not success:
crawl_page(url)
success = True
except:
attempts += 1
if attempts == 3:
break
attempts = 0
success = False
while attempts < 3 and not success:
    try:
        crawl_page(url)
        success = True
    except:
        attempts += 1
        if attempts == 3:
            break

新的解决方案:retrying

retrying是一个 Python的重试包,可以用来自动重试一些可能运行失败的程序段。retrying提供一个装饰器函数retry,被装饰的函数就会在运行失败的条件下重新执行,默认只要一直报错就会不断重试。

import random
from retrying import retry
@retry
def do_something_unreliable():
if random.randint(0, 10) > 1:
raise IOError("Broken sauce, everything is hosed!!!111one")
else:
return "Awesome sauce!"
print(do_something_unreliable())
import random
from retrying import retry

@retry
def do_something_unreliable():
    if random.randint(0, 10) > 1:
        raise IOError("Broken sauce, everything is hosed!!!111one")
    else:
        return "Awesome sauce!"

print(do_something_unreliable())

如果我们运行have_a_try函数,那么直到random.randint返回5,它才会执行结束,否则会一直重新执行。

retry还可以接受一些参数,这个从源码中Retrying类的初始化函数可以看到可选的参数:

  • stop_max_attempt_number:用来设定最大的尝试次数,超过该次数就停止重试
  •  stop_max_delay:比如设置成10000,那么从被装饰的函数开始执行的时间点开始,到函数成功运行结束或者失败报错中止的时间点,只要这段时间超过10秒,函数就不会再执行了
  • wait_fixed:设置在两次retrying之间的停留时间
  • wait_random_min和wait_random_max:用随机的方式产生两次retrying之间的停留时间
  • wait_exponential_multiplier和wait_exponential_max:以指数的形式产生两次retrying之间的停留时间,产生的值为2^previous_attempt_number * wait_exponential_multiplier,previous_attempt_number是前面已经retry的次数,如果产生的这个值超过了wait_exponential_max的大小,那么之后两个retrying之间的停留值都为wait_exponential_max。这个设计迎合了exponential backoff算法,可以减轻阻塞的情况。
  • 我们可以指定要在出现哪些异常的时候再去retry,这个要用retry_on_exception传入一个函数对象:
def retry_if_io_error(exception):
return isinstance(exception, IOError)
@retry(retry_on_exception=retry_if_io_error)
def read_a_file():
with open("file", "r") as f:
return f.read()
def retry_if_io_error(exception):
    return isinstance(exception, IOError)

@retry(retry_on_exception=retry_if_io_error)
def read_a_file():
    with open("file", "r") as f:
        return f.read()

在执行read_a_file函数的过程中,如果报出异常,那么这个异常会以形参exception传入retry_if_io_error函数中,如果exception是IOError那么就进行retry,如果不是就停止运行并抛出异常。

我们还可以指定要在得到哪些结果的时候去retry,这个要用retry_on_result传入一个函数对象:

def retry_if_result_none(result):
return result is None
@retry(retry_on_result=retry_if_result_none)
def get_result():
return None
def retry_if_result_none(result):
    return result is None

@retry(retry_on_result=retry_if_result_none)
def get_result():
    return None

在执行get_result成功后,会将函数的返回值通过形参result的形式传入retry_if_result_none函数中,如果返回值是None那么就进行retry,否则就结束并返回函数值。

参考资料:


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK