社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

Python退避及重试装饰器:backoff

Python程序员 • 6 年前 • 948 次点击  

小编注

退避,指的是操作失败,等一段时间再重试,而不是立即重试的行为。其意义在于期望被调用的资源能够在这段时间里自行恢复。

退避和重试的函数装饰器

此模块提供函数装饰器,该函数装饰器可用于包装函数,以便函数重试直到满足某些条件为止。当访问可能出现间歇性故障的不可靠资源(如网络资源和外部API)时,它应该有用。一般来说,它还可以用于外部生成内容的动态轮询资源。

装饰器既支持同步代码的常规功能,也支持异步代码的asyncio的协同程序。

示例

由于Kenneth Reitz的requests模块已经成为Python中同步HTTP客户端的行业标准,因此下面使用该模块编写了网络示例,但是backoff模块根本不需要它。

@backoff.on_exception

当指定异常被引发时,使用on_exception装饰器重试。这里有一个例子,当出现任何requests异常时,使用指数退避(即退避时间指数增长):

对于需要多个异常类型采取相同退避行为的情况,装饰器还将接受异常元组:

放弃的条件

可选参数可以指定要放弃的条件。

关键字参数max_time指定在放弃之前的总时间的最大秒数。

关键字参数max_tries指定在放弃之前对目标函数进行调用的最大次数。

在某些情况下,可能需要检查引发异常的实例本身,以确定它是否满足可重试条件。giveup关键字参数可用于指定一个函数,该函数接受异常并在不应该重试异常时返回真值:

当放弃事件发生时,问题中的异常重新引发,因此调用on_exception-decorated函数的代码可能仍然需要执行异常处理。

@backoff.on_predicate

当目标函数返回值符合某个特定条件时,on_predicate装饰器会安排重试。当为外部生成内容轮询资源时,这可能是有用的。

下面是一个例子,当目标函数的返回值为空列表时,使用斐波那契序列退避(退避时间满足):

在初始化等待生成器时传递额外的关键字参数,因此在初始化fibo生成器时,上面的max_value参数作为关键字参数传递。

当未指定断言函数时,默认做返回值的假值测试,因此上面可以写的更简洁些:

更简单地说,一个继续每秒钟轮询直到得到非假结果的函数可以像这样定义:

Jitter

jitter算法可以向任何一个退避装饰器提供jitter关键字参数。这个参数应该是一个函数,接受原始的退避值并返回它的jittered的对应项。

从1.2版开始,默认的jitter函数backoff.full_jitter实现了AWS架构博客的指数退避和Jitter帖子中定义的“Full Jitter”算法。注意,使用此算法,等待生成器所产生的时间实际上是等待的最大时间量。

以前版本的退避默认添加随机数毫秒(高达1s)到原始睡眠值。如果需要,这种行为现在可以作为backoff.random_jitter

使用多个装饰器

还可以组合退避装饰器以指定不同情况下的不同退避行为:

运行时配置

装饰函数on_exceptionon_predicate通常在导入时确定参数。当关键字参数作为常量值传递时,这很好,但是假设我们想要查阅带有配置选项的字典,这些配置选项仅在运行时可用。相关值在导入时不可用。取而代之的是,装饰函数可以通过在运行时执行函数来获得参数值:

事件处理

两个backoff装饰器都可以选择使用关键字参数on_successon_backoffon_giveup接受事件处理程序函数。这在报告统计或执行其他自定义日志方面可能有用。

处理程序必须是一个接受一个字典参数的一元签名的可调用文件。此字典包含调用的详细信息。有效键包括:

  • target:引用调用的函数或方法

  • args:func的位置参数

  • kwargs : func的关键字参数

  • tries: 到目前为止的调用次数

  • elapsed: 到现在为止经过的时间

  • wait: 等待秒(仅on_backoff处理)

  • value: 触发退避值(仅用on_predicate装饰器)

打印回退事件的细节的处理程序可以实现如下:

每个事件类型的多个处理程序

在所有情况下,处理函数的迭代被接受,依次调用它们。例如,你可以提供一个简单的处理函数列表,作为on_backoff关键字参数的值:

获取异常信息

on_exception装饰器的情况下,所有on_backoffon_giveup处理程序都从异常块中调用,以处理异常。因此,异常信息可以通过python标准库(特别是sys.exc_info()traceback模块)提供给处理函数。

异步代码

要在基于asyncio的异步代码中使用backoff,您只需要将backoff.on_exception backoff.on_predicate应用于协同例程。您还可以使用接口是相同的on_successon_backoffon_giveup事件处理程序的协同程序。

下面的示例使用aiohttp 异步HTTP Client/Server库。

采用Python 3.5及以上的async defawait语法:

如果使用Python 3.4,可以使用@asyncio.coroutine和yield from:

日志配置

错误和回退和重试尝试被记录到“退避”记录器。默认情况下,此记录器配置为NullHandler,因此除非配置处理程序,否则将没有输出。从编程上讲,这可以用简单的方法来完成:

记录默认级别是INFO,它对应于重试事件发生时的日志记录。如果您只希望在发生giveup事件时记录,则将记录器级别设置为ERROR。


英文原文:https://github.com/litl/backoff/
译者:张新英



今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/li3P4DAQTO
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/23379
 
948 次点击