目录

  1. 动机
  2. 用法
    2.1 基本用法
    2.2 何时停止
    2.3 尝试间得等待
    2.4 何时retry
    2.5 其它
  3. 源码分析

1. 动机

很多时候,我们都喜欢为代码加入retry功能。比如oauth验证,有时候网络不太灵,我们希望多试几次。

这些retry应用的场景看起来不同,其实又很类似。都是判断代码是否正常运行,如果不是则重新开始。

那么,有没有一种通用的办法来实现呢?

  • 简介
    Tenacity1是一个通用的retry库,简化为任何任务加入重试的功能。

它还包含如下特性:

通用的装饰器API
可以设定重试停止的条件(比如设定尝试次数)
可以设定重试间的等待时间(比如在尝试之间使用幂数级增长的wait等待)
自定义在哪些Exception进行重试
自定义在哪些返回值的情况进行重试
协程的重试

2. 用法

2.1 基本用法

from tenacity import *# 基础的用法,会一直重试下去,直到函数没有抛出异常,正常返回值@retry
def never_give_up_never_surrender():print("一直重试,忽略exceptions,重试间没有等待时间")raise Exception

2.2 何时停止

让我们加入停止的条件.

例如,在达到尝试次数后停下来:

@retry(stop=stop_after_attempt(7))
def stop_after_7_attempts():print("尝试7次后停下")raise Exception
在10秒后,如果仍然没有成功,则停下:
@retry(stop=stop_after_delay(10))
def stop_after_10_s():print("10秒后停止")raise Exception

可以使用|操作符,来组合多种条件:

@retry(stop=(stop_after_delay(10) | stop_after_attempt(5)))
def stop_after_10_s_or_5_retries():print("10秒后,或者尝试5次后,停下来")raise Exception

2.3 尝试间的等待

很多事并不是越快越好。所以,让我们在重试的尝试之间加入一些间隔时间:

@retry(wait=wait_fixed(2))
def wait_2_s():print("每次重试间都有2秒间隔")raise Exception

间隔可以是随机的:

@retry(wait=wait_random(min=1, max=2))
def wait_random_1_to_2_s():print("重试间隔1-2秒")raise Exception

还可以加入指数曲线形式的间隔:

@retry(wait=wait_exponential(multiplier=1, min=4, max=10))
def wait_exponential_1():print("开始的时候等待 2^x * 1 秒,最少等待4秒,最多10秒,之后都是等待10秒")raise Exception

多核在竞争一个共享的资源,使用指数间隔可以将冲突最小化:

@retry(wait=wait_random_exponential(multiplier=1, max=60))
def wait_exponential_jitter():print("随机等待 2^x * 1 秒,最多60秒,之后都是等待60秒")raise Exception

可以自定义每次等待时长:

@retry(wait=wait_chain(*[wait_fixed(3) for i in range(3)] +[wait_fixed(7) for i in range(2)] +[wait_fixed(9)]))
def wait_fixed_chained():print("前三次等待3秒,后两次等待7秒,最后一次等待9秒")raise Exception

2.4 何时retry

默认情况下,只有函数抛出异常时才会retry。

你可以设置在制定的异常才进行retry:

@retry(retry=retry_if_exception_type(IOError))
def might_io_error():print("只有在IOError的时候进行retry,其它时候照常抛出错误")raise Exception

可以在判断返回值是否是需要的情况下进行retry:

def is_none_p(value):return value is None@retry(retry=retry_if_result(is_none_p))
def might_return_none():print("因为返回值是None,所以这个函数会一直retry")# 这样写也是可以的,不用修改原来的代码
retry_version_func = retry(retry=retry_if_result(is_none_p))(might_return_none)

当然,这里也可以组合多个条件:

def is_none_p(value):return value is None@retry(retry=(retry_if_result(is_none_p) | retry_if_exception_type()))
def might_return_none():print("在抛出任何异常,或者返回值是None的情况下,进行retry")

2.5 其它

在函数体内,你可以手动抛出TryAgain错误,进行重试:

@retry
def do_something():result = something_else()if result == 23:raise TryAgain

通过参数reraise=True,可以抛出函数最后一次抛出的异常。如果没有设定,会抛出RetryError:

@retry(reraise=True, stop=stop_after_attempt(3))
def raise_my_exception():raise MyException("Fail")try:raise_my_exception()
except MyException:print('MyException会被抛出')

在重试的前后,记录日志:

import logginglogging.basicConfig(stream=sys.stderr, level=logging.DEBUG)logger = logging.getLogger(__name__)# 重试前记录
@retry(stop=stop_after_attempt(3), before=before_log(logger, logging.DEBUG))
def raise_my_exception():raise MyException("Fail")# 重试后记录
@retry(stop=stop_after_attempt(3), after=after_log(logger, logging.DEBUG))
def raise_my_exception():raise MyException("Fail")

你可以获取retry的相关统计数据:

@retry(stop=stop_after_attempt(3))
def raise_my_exception():raise MyException("Fail")try:raise_my_exception()
except Exception:passprint(raise_my_exception.retry.statistics)

3. 源码分析

这个库在代码和项目方面都是典范,同时API设计的也是相当漂亮。

这个库对python装饰器的用法已经炉火纯青,基本所有的情景都有用到。有兴趣的同学可以通过下面几个点去看:

retry装饰器为什么可以无参数版本/有参数版本混合使用
retry装饰器为什么可以作用函数和方法
retry装饰器为什么可以作用于asyncio协程,tornado协程,普通函数

tenacity -- Python中一个专门用来retry的库相关推荐

  1. 【AMAD】tenacity -- Python中一个专门用来retry的库

    动机 简介 用法 基本用法 何时停止 尝试间的等待 何时retry 其它 热度分析 源码分析 个人评分 动机 很多时候,我们都喜欢为代码加入retry功能.比如oauth验证,有时候网络不太灵,我们希 ...

  2. python中一个星号(*)与两个星号(**)的作用

    python中一个星号(*)与两个星号(**)的作用 目录 python中一个星号(`*`)与两个星号(`**`)的作用 一.一般用法 概述: 1.`*`表示乘法,`**`表示幂 2.`*`表示打包解 ...

  3. python try语句例题_在Python中,一个try语句只能和一个except语句搭配。_学小易找答案...

    [单选题]言语和语言不同,言语是_____. [填空题]901x28= [判断题]在Python中,类中定义的类的成员(属性)或类方法,默认情况下都为公有的. [单选题]Outlines can be ...

  4. [python-thirdLib] Python中第三方的用于解析HTML的库:BeautifulSoup

    From: http://www.crifan.com/python_third_party_lib_html_parser_beautifulsoup/ 背景 在Python去写爬虫,网页解析等过程 ...

  5. 帮你解剖Python的一个轻量级桌面GUI开发第三方库:Eel,让它体无完肤

    Python的一个轻量级桌面GUI开发第三方库:Eel 一.Eel介绍 二.资源库eel的安装 三.文件结构和简单的hello介绍 3.1 文件结构 3.2 代码:hello1.py 3.3 main ...

  6. python中一个等于号和两个等于号_Python中is与双等于号“==”的区别

    Python有两个用于相等比较的运算符,"is"和"=="(等于).在这篇文章中,我将带你们了解Python中"is"和"==&q ...

  7. python中一个等于号和两个等于号_python中is与双等于号“==”的区别示例详解

    前言 在开始本文之前,首先要知道Python中对象包含的三个基本要素,分别是:id(身份标识).python type()(数据类型)和value(值).is和==都是对对象进行比较判断作用的,但对对 ...

  8. 在python中一个复数的虚部用i表示_以3为实部4为虚部,Python复数的表达形式为___________或________。_学小易找答案...

    [填空题]Python 源代码程序编译后的文件扩展名为_________. [单选题]1. Why did the old Watchdog say that the sun will teach t ...

  9. python中一个字符视为长度为1的字符串_【Python】笔试题知识点小结(1)

    题目来源:牛客网 今天开始复习巩固一下基础知识点- 蓝色表示题干,红色表示答案,黑色表示知识点. 1.下列代码的运行结果是? print 'a' < 'b' < 'c'True 1)pyt ...

  10. python中turtle画老虎_通过Turtle库在Python中绘制一个鼠年福鼠

    turtle库是一个很经典的绘图库,其最初来自于1967年创造的logo编程语言,之后被Python编写放到了Python的内置模块中.网络上有很多借助于turtle绘制精美图像的案例.比如小猪佩奇. ...

最新文章

  1. 计算机工程实践,【计算机工程论文】计算机工程实践能力培养(共3056字)
  2. NOIP2012 文化之旅
  3. 设计模式之_工厂系列_01
  4. 深入理解程序执行原理
  5. Spring boot(九):定时任务
  6. bootstrap3 表单构建器_FastReport.NET报表设计器连接到OracleDB关系数据库
  7. java用while循环语句输出1-100内的奇数和
  8. (计算机组成原理)第二章数据的表示和运算-第三节2:IEEE754标准
  9. ABAP基础篇-语法-数据类型
  10. LeetCode 22. Generate Parentheses
  11. stl 向量_C ++ STL中的向量delete()和clear()
  12. 收集的一些discuz插件常用插件。
  13. 【海康威视】WPF客户端二次开发:【1】监控视频画面预览(SDK初始化、设备登录、监控画面预览)
  14. xThunder —— 完美支持Firefox的迅雷,旋风调用扩展
  15. 在vue中实现父组件调用子组件以及传值
  16. 2018计算机cpu调研,2018年1月电脑CPU天梯图
  17. android后台进程数目限制
  18. 宋体能力从业的一些感悟
  19. 二建机电实务视频教程
  20. R语言学习(一)前言

热门文章

  1. c语言中变量属性,C语言学习笔记--C语言中变量的属性关键字
  2. 脉冲云中使用的ajv
  3. 素描小子跑酷html5游戏在线玩,体验Html5实现的在线素描及绘画设计
  4. 根据pc值确定出错的代码位置
  5. 小虎电商浏览器:店透视应该如何查黑号?
  6. 阿里笔试--智能对话简化版之query指令槽位识别
  7. java中十六进制数_Java中的十六进制到整数
  8. 剑与家园服务器维护,《剑与家园》杀鸡取卵式运营 如何拯救短命的区服?
  9. 一元享移动怎么样_移动新套餐:18元享“全免流”+1元1G流量,阿里鱼卡要遭殃?...
  10. 拉卡拉支付率先布局B端市场