Отличие заключается в том, что во втором фрагменте кода вы больше не украшаете функцию, а получаете сопрограмму.Они возвращаются только после выполнения в цикле событий.
Добавление отладочной печати для 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
на самом деле сама программа, а не ее результат.Следовательно, ваша retry_if_result_none
функция возвращает False
, и цикл повторения завершается после первой итерации.
В основном это проблема синхронизации.Ваш синхронный декоратор не синхронизирован (очень каламбур) с асинхронным выполнением сопрограммы в цикле событий.
Вам придется использовать асинхронный декоратор, чтобы иметь возможность await
результатасопрограмма.Я принял этот базовый, но функциональный asnyc retry decorator , чтобы принимать решение на основе возвращаемого значения вашей функции, как это делает retrying
.
Обратите внимание, что внутренний wrapper
функция - сопрограмма, которая await
s является результатом декорированной сопрограммы 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
и упомянутого оператора print
в функции retry_if_result_none
.