python - 使用 run_until_complete 运行时重试不起作用

标签 python retrying

首先,我运行了这样的代码,并且重试工作正常。

# -*- coding:utf-8 -*-
from retrying import retry
import asyncio
import time
num = 0;

def retry_if_result_none(result):
    return result is None

@retry(retry_on_result=retry_if_result_none) 
def get_result():
    global num;
    num += 1;
    if num < 10:
        print('Retry.....');
        return None;
    else:
        return True;
    time.sleep(1);

def call():
    end = get_result();
    if end:
        print('ok');
    else:
        print('over')

if __name__ == '__main__':
    call();

Output:
Retry.....
Retry.....
Retry.....
Retry.....
Retry.....
Retry.....
Retry.....
Retry.....
Retry.....
ok

其次,我这样编辑代码,然后再次运行,但收到​​不同的结果。

# -*- coding:utf-8 -*-
from retrying import retry
import asyncio
import time
num = 0;

def retry_if_result_none(result):
#    print("retry_if_result_none") 
    return result is None

@retry(retry_on_result=retry_if_result_none) 
async def get_result():
    global num;
    num += 1;
    if num < 10:
        print('Retry.....');
        return None;
    else:
        return True;
    time.sleep(1);

async def call():
    end = await get_result();
    if end:
        print('ok');
    else:
        print('over')

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(call())

Output:    
Retry.....
over

如图所示,重试在第二个代码中不起作用。不同的是我把call()放在loop.run_until_complete方法中,如何解决这个问题?

最佳答案

相关的区别在于,在第二个代码片段中,您不再装饰函数,而是装饰协程。它们仅在事件循环中执行后才返回。

结果的调试打印添加到您的检查函数中,并使用同步代码示例运行它,显示预期的结果:

def retry_if_result_none(result):
    print(result)
    return result is None

Retry.....
None
Retry.....
None
True # Note: I have set the condition to num < 3
ok

如果您对异步版本执行相同的操作,您会看到问题:

<coroutine object get_result at 0x0322EF90>
Retry.....
over

所以 result 实际上是协程本身,而不是它的结果。因此,您的 retry_if_result_none 函数返回 False 并且重试循环在第一次迭代后终止。

这基本上是一个时间问题。您的同步装饰器与事件循环中协程的异步执行不同步(非常有意的双关语)。

您必须使用异步装饰器才能等待协程的结果。我已采纳this basic but functional asnyc retry decorator根据函数的返回值做出决定,就像 retrying 所做的那样。

请注意,内部wrapper函数是一个协程,它await是装饰协程get_result的结果。

def tries(func):
    def func_wrapper(f):
        async def wrapper(*args, **kwargs):
            while True:
                try:
                    if func(await f(*args, **kwargs)):
                        continue
                    else:
                        break
                except Exception as exc:
                    pass
            return True
        return wrapper
    return func_wrapper

@tries(retry_if_result_none)
async def get_result():
    [...]

在异步代码上使用它会产生预期的输出:

Retry.....
None
Retry.....
None
[...]
Retry.....
None
True
ok

除了在 get_result 上切换装饰器以及在 retry_if_result_none 函数中提到的 print 语句之外,其余代码未进行任何更改。

关于python - 使用 run_until_complete 运行时重试不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53537109/

相关文章:

python - [Python]创建虚拟环境失败

python - 在python中,如何只为函数存储一次 'constants'?

python - 将多个参数传递给 python 中重试的 retry_on_exception 参数

python - 如何从 Web 服务器日志文件中提取数据并解析请求行部分?

python - 使用 lxml.etree 解析本地文件

Python:binascii.a2b_hex 给出 "Odd-length string"