aioschedule使用异常捕获装饰器无法停止报错异步任务问题求解
问题根因
- 你使用的装饰器为同步逻辑,而被装饰的
bad_task是异步协程函数:直接调用异步函数不会执行内部逻辑,仅会返回协程对象,因此你的try/except块无法捕获到协程执行时抛出的异常,异常会在事件循环调度协程时直接抛出,脱离捕获范围。 - 同步schedule库执行同步任务时会直接读取函数返回值判断是否为
schedule.CancelJob,但aioschedule需要等待协程执行完成后才能读取返回值,原装饰器的同步逻辑无法将CancelJob返回给aioschedule的调度器。
修复方案
将装饰器的包装函数改为异步逻辑,在内部await执行目标协程,即可正确捕获异常并返回CancelJob终止任务,修改后代码如下:
import functools import aioschedule as schedule import asyncio def catch_exceptions(cancel_on_failure=False): def catch_exceptions_decorator(job_func): @functools.wraps(job_func) async def wrapper(*args, **kwargs): # 改为异步包装函数 try: return await job_func(*args, **kwargs) # await执行异步任务 except: import traceback traceback.print_exc() # 可选:打印异常栈 if cancel_on_failure: return schedule.CancelJob return wrapper return catch_exceptions_decorator @catch_exceptions(cancel_on_failure=True) async def bad_task(): print(1 / 0) async def main(): # 主函数改为异步写法更符合异步编程规范 schedule.every().minute.do(bad_task) while True: await schedule.run_pending() await asyncio.sleep(1) # 避免空转占用过高CPU if __name__ == '__main__': asyncio.run(main())
验证说明
修改后代码运行时,首次执行bad_task触发异常后,装饰器会返回schedule.CancelJob,aioschedule调度器识别到该返回值后会自动移除该定时任务,不会再次触发执行,异常也不会持续抛出。
内容的提问来源于stack exchange,提问作者Swarnim Kumar
相关产品推荐
相关产品推荐

