高CPU负载下Asyncio协程无报错终止问题求助:部分任务离奇中断无任何反馈
我遇到了一个非常诡异的问题:我的应用有一个POST入口,负责接收订单ID列表,处理完每个订单后需要通知外部API对应的订单金额。我们用异步任务的方式实现了这个逻辑,代码如下:
order_details_tasks = [ asyncio.create_task( self.launch_individual_order_details(order), name=f"task_order_{order.id}", ) for order in active_orders ] results = await asyncio.gather(*order_details_tasks, return_exceptions=True) for task, result in zip(order_details_tasks, results): if isinstance(result, Exception): print(f"⚠️ Task '{task.get_name()}' raised an exception: {result}") else: print(f"✅ Task '{task.get_name()}' succeeded with result: {result}")
其中launch_individual_order_details(order)函数会先执行一些非I/O逻辑,然后执行以下核心代码:
logger.debug(f"Sending order details with success for order: {order.id}") await order_service.send_order_request(order)
在send_order_request函数里,我们会先在Transaction表中创建一条记录(包含订单ID、对应金额,状态设为pending),然后用aiohttp.Client发送HTTP请求到外部API。之后根据请求结果更新交易状态:请求成功就把状态改成Success,失败则改成Error。
现在的问题来了:当Pod的CPU使用率达到我们设置的资源限制的70%左右、系统处于中等负载时,部分任务会直接中断执行,而且完全不反馈任何错误信息。
我们是通过压测后的校验脚本发现这个问题的:有些订单对应的Transaction记录一直停留在pending状态,说明连外部API的请求都没发出去。更奇怪的是,这些订单对应的任务既没有出现在成功日志✅ Task '{task.get_name()}' succeeded with result: {result}里,也没有出现在错误日志⚠️ Task '{task.get_name()}' raised an exception: {result}里。
我们甚至把事件循环的日志级别调到了debug,也找不到和这些消失的任务相关的任何错误记录。唯一能确定的是,任务执行到了这条debug日志就戛然而止:
logger.debug(f"Sending order details with success for order: {order.id}")
之后就没有任何后续操作了,Transaction的状态也一直是pending。
我写了一个最小复现脚本(虽然不确定运行时会不会触发同样问题,但能完整还原我们的核心逻辑):
import asyncio import aiohttp async def stack_overflow_script(active_orders): order_details_tasks = [ asyncio.create_task( launch_individual_order_details(order), name=f"task_order_{order}", ) for order in active_orders ] results = await asyncio.gather(*order_details_tasks, return_exceptions=True) for task, result in zip(order_details_tasks, results): if isinstance(result, Exception): print(f"⚠️ Task '{task.get_name()}' raised an exception: {result}") else: print(f"✅ Task '{task.get_name()}' succeeded with result: {result}") async def launch_individual_order_details(order): print(f"Sending round details for play: {order}") await send_order_request(order) async def send_order_request(order): params = dict(order_id=order) try: async with aiohttp.ClientSession() as session: async with session.request( "POST", url="https://stack-mre.free.beeceptor.com/order", timeout=10, json=params ) as resp: resp_json = await resp.json() return resp_json except asyncio.TimeoutError: return asyncio.run(stack_overflow_script([2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]))
简单总结就是:高负载(CPU达70%资源限制)时,部分异步任务会悄无声息地“消失”——既不报错也不返回结果,完全找不到任何执行痕迹。有没有大佬遇到过类似的情况,能帮忙分析下可能的原因吗?
备注:内容来源于stack exchange,提问作者Pedro Silva

