Python如何优雅地使用重试:tenacity

news2025/1/21 12:22:09

1 缘起

项目中使用了第三方服务,和上一篇文章一样:SpringBoot中如何优雅地使用重试https://blog.csdn.net/Xin_101/article/details/134617868
在调用第三方服务时,出现第三方服务连接不到的情况,为了保证服务的相对稳定,
当调用第三方服务出现异常时,进行重试,
本次的项目是Python语言开发的,因此,选择了灵活、功能强大的Tenacity框架。

2 Tenacity

https://tenacity.readthedocs.io/en/latest/
在这里插入图片描述

2.1 简介

Tenacity是Python的重试框架,用于简化重试逻辑的编写,
直接在Tenacity中提供的重试方法中配置相关参数即可实现重试功能,
参数化重试机制,如重试次数、时间间隔、重试的异常情况等,
提高开发效率。

2.2 retry方法

通过retry方法实现在指定异常情况下进行重试。
配置重试参数,在需要重试的方法上添加retry注解即可实现重试。
retry源码如下:
tenacity.retry
在这里插入图片描述

retry参数源码如下:
在这里插入图片描述

常用参数解析:

序号参数:描述
1max_retries最大重试次数
2retry_exception触发重试的异常类型
3reraise重新抛出异常开关:true:重新抛出异常;false:不重新抛出异常
4multiplier重试时间倍率,时间间隔:multiplier * 2^(n-1),n为执行次数
5min_seconds最小重试时间间隔
6max_seconds最大重试时间间隔

其中,

  • max_retries是执行的总次数,重试次数即为执行的总次数-1,如max_retries=5,重试4次,总共执行5次。
  • retry_exception用于配置重试的异常条件,即在何种异常出现时进行重试。
  • reraise是重试后是否抛出异常的标识,配置为true时,当达到重试最大次数时,重新抛出异常,给下游捕获,当配置为false时,不抛出异常。
  • min_seconds:最小时间间隔,当重试次数计算的时间间隔小于min_seconds时,使用min_seconds的值作为时间间隔,否则使用计算时间间隔。
  • max_seconds:最大时间间隔,当重试次数计算的时间间隔大于max_seconds时,使用max_seconds作为时间间隔,避免延迟时间爆炸,限定重试间隔上限/上边界。
  • multiplier用于配置重试时间间隔比率,时间间隔:multiplier * 2^(n-1),n为执行次数,这个可以参见源码,如下图所示,时间间隔为result=self.multiplier * exp,而exp=self.exp_base ** (retry_state.attempt_number - 1),因此时间间隔为:multiplier * 2^(n-1),最终的重试时间间隔是在计算结果result、最小时间间隔和最大时间间隔中取出的。
    位置:tenacity.wait.wait_exponential
    在这里插入图片描述

2.3 配置retry参数

这里我们对retry方法进行一层包装,有些多余,
先这样写吧,如下:
在这里插入图片描述

2.4 指定方法上使用retry

完成retry方法参数配置后,在需要重试的方法中使用retry框架,
首先初始化retry的方法,
然后在执行的方法上添加注解。
在这里插入图片描述
执行结果如下图所示,
按照上面的retry配置,可知min_seconds=4s,max_seconds=10s,max_retries=5,multiplier=1
即重试4次,

  • 时间间隔:第二次~第一次:time_interval=1*2^(2-1)=1s,time_interval<min_seconds,因此使用4s;
  • 时间间隔:第三次~第二次:time_interval=1*2^(3-1)=4s,time_interval=min_seconds,因此使用4s;
  • 时间间隔:第四次~第三次:time_interval=1*2^(4-1)=8s,min_seconds<time_interval<max_seconds,因此使用8s;

在这里插入图片描述

2.5 完整样例

"""
重试测试

@author xindaqi
@since 2023-12-02 16:34
"""
from typing import Callable, Any
from datetime import datetime
import logging


from tenacity import (
    before_sleep_log,
    retry,
    retry_if_exception_type,
    stop_after_attempt,
    wait_exponential,
)

logger = logging.getLogger(__name__)


def retry_decorator(max_retries: int, retry_exception: "RetryBaseT" = retry_if_exception_type(), reraise=True, multiplier=1, min_seconds=4, max_seconds=10) -> Callable[[Any], Any]:
    """重试装饰器

    :param max_retries: 最大重试次数
    :param retry_exception: 触发重试的异常类型
    :param reraise: 重新抛出异常开关:true:重新抛出异常;false:不重新抛出异常
    :param multiplier: 重试时间倍率,时间间隔:multiplier * 2^(n-1),n为执行次数
    :param min_seconds: 最小重试时间间隔
    :param max_seconds: 最大重试时间间隔
    :return: 重试对象
    """
    return retry(
        reraise=reraise,
        stop=stop_after_attempt(max_retries),
        wait=wait_exponential(multiplier=multiplier, min=min_seconds, max=max_seconds),
        retry=retry_exception,
        before_sleep=before_sleep_log(logger, logging.WARNING),
    )


def function_with_retry(max_retries, retry_exception):
    retry_decorator_init = retry_decorator(max_retries, retry_exception)

    @retry_decorator_init
    def run():
        now = datetime.now()
        current_time = now.strftime("%Y-%m-%d %H:%M:%S")
        print(">>>>>>>>Current time:{}".format(current_time))
        a = 1/0
    return run()


if __name__ == "__main__":
    exception = (
        retry_if_exception_type(ZeroDivisionError))
    function_with_retry(5, exception)

3 小结

(1)Tenacity重试框架,提供重试参数配置,简单易用,提高开发效率;
(2)重试参数有max_retries(最大执行次数)、reraise(重新抛出异常标识,如果达到重试次数上限后,是否抛出原生异常给上游调用方),min_seconds最小的时间间隔,即重试的时间间隔最小只能为min_seconds,max_seconds是最大时间间隔,即最大的延迟时间为max_seconds,为重试时间间隔做了限制,保证间隔的合理;
(3)重试时间间隔计算公式为:time_interval=multiplier*2^(n-1),n为重试次数,最终的延迟时间间隔从time_interval、min_seconds和max_seconds中取,计算公式:max(max(0, min_seconds), min(time_interval, max_seconds));
(4)Tenacity可以配置多种异常类型,当出现这些异常时进行重试,细粒度控制重试。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1279979.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

糟了,数据库崩了,又好像没崩

前言 2023 年某一天周末&#xff0c;新手程序员小明因为领导安排的一个活来到公司加班&#xff0c;小明三下五除二&#xff0c;按照领导要求写了一个跑批的数据落库任务在测试环境执行 &#xff0c;突然间公司停电了&#xff0c;小明大惊&#xff0c;“糟了&#xff0c;MySQL …

每天一点python——day84

#每天一点Python——84 #异常处理机制try—except—else #异常处理机制try—except—else如果try块中没有抛出异常&#xff0c;则执行else块&#xff0c;如果try中抛出异常&#xff0c;则执行except块#示例&#xff1a; try:a int(input(请输入第一个整数&#xff1a;))b in…

【JavaEE】多线程(3) -- 线程等待 wait 和 notify

目录 1. wait()⽅法 2. notify()⽅法 3. notifyAll()⽅法 4. wait 和 sleep 的对⽐&#xff08;⾯试题&#xff09; 由于线程之间是抢占式执⾏的, 因此线程之间执⾏的先后顺序难以预知. 但是实际开发中有时候我们希望合理的协调多个线程之间的执⾏先后顺序. 完成这个协调⼯…

【ArcGIS Pro微课1000例】0044:深度学习--面部模糊(马赛克)

本文讲解ArcGIS Pro中通过深度学习工具实现人脸面部模糊,起到马赛克的作用。 文章目录 一、效果对比二、工具介绍三、案例实现一、效果对比 原始图片: 深度学习后的模糊照片: 二、工具介绍 本工具为ArcGIS Pro工具箱中的深度学习工具中的:使用深度学习分类像素,如下所示…

ChatGPT 的 18 种玩法,你还不会用吗?

你确定&#xff0c;你会使用 ChatGPT 了吗&#xff1f; 今天给大家整理了 18 种 ChatGPT 的用法&#xff0c;看看有哪些方法是你能得上的。 用之前我们可以打开R5Ai平台&#xff0c;可以免费使用目前所有的大模型 地址&#xff1a;R5Ai.com 语法更正 用途&#xff1a;文章…

ER图是什么,怎么画?

ER图&#xff08;Entity-Relationship Diagram&#xff09;是一种用于描述实体间关系的图形化表示方法。它主要用于数据库设计&#xff0c;可以清晰地展示实体、属性和实体间的联系。常用的ER图类型包括&#xff1a; 实体-关系模型&#xff08;Entity-Relationship Model&…

Shutdown Signal: channel error; protocol method: #method<channel.close>

完整异常信息&#xff1a; Shutdown Signal: channel error; protocol method: #method<channel.close>(reply-code404, reply-textNOT_FOUND - no exchange fanoutExchange in vhost /, class-id60, method-id40) 意思是找不到名字是 fanoutExchange 的虚拟机 就是虚拟机…

基于SSH三大框架的员工管理系统

基于SSH三大框架的员工管理系统 摘要 本系统为本人学习SSH三大框架时所做的整合实例&#xff0c;系统角色包括普通用户和管理员两种&#xff0c;首页有管理员登录入口链接。系统功能主要包括管理员对用户的基本增、删、改、查和分页显示用户信息等。 系统环境 本系统使用ec…

Gossip 协议

Gossip 协议 背景 在分布式系统中&#xff0c;不同的节点进行数据/信息共享是一个基本的需求。 一种比较简单粗暴的方法就是 集中式发散消息&#xff0c;简单来说就是一个主节点同时共享最新信息给其他所有节点&#xff0c;比较适合中心化系统。这种方法的缺陷也很明显&…

App测试之App日志收集及adb常用命令

文章目录 前言一、adb是什么1.APP测试收集手机日志常用的工具2.adb下载与安装3.ADT/SDK/ADB是什么4.adb连接真机 二、adb常用命令三、android系统日志文件1.logcat日志文件2.logcat日志文件分析 四、分析crash & ANR 日志1.发生crash如何分析2.发生ANR如何分析 总结扩展&am…

队列顺序存储(详解)

队列是一种常见的数据结构&#xff0c;它是一种先进先出&#xff08;First-In-First-Out, FIFO&#xff09;的线性表。在队列中&#xff0c;数据元素按照插入的顺序排列&#xff0c;最先插入的元素在队列的前面&#xff0c;最后插入的元素在队列的后面。类比生活中排队购物的情…

登录界面(flex布局练习)

练习&#xff1a;登录界面在我们网页制作的过程中经常遇见&#xff0c;所以请你编写一个界面联系一下&#xff0c;这个可以增加一些动画或者是其他的效果&#xff0c;当然越帅越好。请使用flex或者其他布局练习 例如&#xff1a; 代码 <!DOCTYPE html> <html lang…

如何做好小红书?9条小红书运营起号心得(必读)

关于小红书运营细节和方法&#xff0c;总结了以下9条起号心得&#xff0c;希望给近期新手们一些经验借鉴。 一、出现一条爆文后的策略当账号新发的一篇笔记流量起飞了&#xff0c;不要急于发布新内容。先让爆文的流量消耗殆尽&#xff0c;等流量开始减少时再发布新笔记。同时&…

2022CVPR(PoseC3D):Revisiting Skeleton-based Action Recognition

Revisiting Skeleton-based Action Recognition 摘要1、引言2、相关工作3、框架3.1. 姿势提取的良好实践3.2.从2D姿势到3D热图体积3.3.基于骨架的动作识别的3D-CNN 4、实验4.2.姿势提取4.3. 3D热图体积的预处理4.4.与GCN的比较4.5. RGBPose-SlowFast4.6.与最先进的比较 5、结论…

C语言-联合和枚举

------------------------------------ --------------- ------ 最慢的步伐不是跬步&#xff0c;而是徘徊&#xff1b; 最快的脚步不是冲刺&#xff0c;而是坚持。 今天来到我们的联合和枚举类型的讲解&#xff1a; 目录 联合体类型 联合体类型的声明 联合体类型的特点 …

Effective Java解读

Effective Java 第一章 引言第二章 创建和销毁对象第1条&#xff1a;用静态工厂方法代替构造器第2条&#xff1a;遇到多个构造器参数时要考虑使用构建器第3条&#xff1a;用私有构造器或者枚举类型强化Singletion属性第4条&#xff1a;通过私有构造器强化不可实例化的能力第5条…

计算机网络的分类

目录 一、按照传输介质进行分类 1、有线网络 2、无线网络 二、按照使用者进行分类 1、公用网 (public network) 2、专用网(private network) 三、按照网络规模和作用范围进行分类 1、PAN 个人局域网 2、LAN 局域网 3、MAN 城域网 4、 WAN 广域网 5、Internet 因特…

canvas基础:fillStyle 和strokeStyle示例

canvas实例应用100 专栏提供canvas的基础知识&#xff0c;高级动画&#xff0c;相关应用扩展等信息。 canvas作为html的一部分&#xff0c;是图像图标地图可视化的一个重要的基础&#xff0c;学好了canvas&#xff0c;在其他的一些应用上将会起到非常重要的帮助。 文章目录 上色…

工具类整理

常用工具类 在java的庞大体系中&#xff0c;其实有很多不错的小工具&#xff0c;也就是我们平常说的&#xff1a;轮子。 CollectionUtils 目前比较主流的是spring的org.springframework.util包下的CollectionUtils工具类。和apache的org.apache.commons.collections包下的Co…

SmartSoftHelp8,应用程序优化,稳定性优化,性能优化,并发承载优化工具

winform 应用全局捕获异常 WPF 应用全局捕获异常 asp.net web 应用全局捕获异常 MVC web 应用全局捕获异常 netcore 应用全局捕获异常 一级缓存&#xff1a;html、cs&#xff0c;js 网页前端缓存设置 二级缓存&#xff1a;asp.net 客户端缓存设置 二级缓存&#xff…