【问题标题】:Retry does not work when running with run_until_complete使用 run_until_complete 运行时重试不起作用
【发布时间】:2018-11-29 10:40:46
【问题描述】:

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

# -*- 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 方法中,如何解决这个问题?

【问题讨论】:

    标签: python retrying


    【解决方案1】:

    相关的区别在于,在你的第二个代码被剪断时,你不再装饰一个函数,而是一个协程。它们只有在事件循环中执行后才会返回。

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

    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 实际上是 couroutine 本身,而不是它的结果。因此,您的 retry_if_result_none 函数返回 False,并且重试循环在第一次迭代后终止。

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

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

    请注意,内部 wrapper 函数是一个协程,awaits 是装饰协程 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 语句之外,您的代码的其余部分没有改变。

    【讨论】:

    • 现在,代码在您的帮助下修改后可以正常工作了。这真的是我的预期。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-14
    • 1970-01-01
    • 1970-01-01
    • 2019-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多