给协程套了 wait_for 五秒超时,主流程确实抛了 TimeoutError 往下走,可那个任务还在写数据库,日志里五秒之后仍有它的输出。碰到这种情况,我一般先确认改动有没有真的生效。
原因不复杂,wait_for 超时会向任务发出取消,协程如果没在 await 点让出控制权,或者把取消异常吃了,取消就不会生效,任务会继续跑到自然结束之后。
「wait_for 超时取消」这个问题文档写得含糊,实际行为以当前版本为准,别照旧版本的结论套。改完顺手把文档补一句,省得下次自己重新推一遍。
try:
await asyncio.wait_for(sync_order(order_id), timeout=5)
except asyncio.TimeoutError:
log.warning('order %s timeout', order_id)
监控和日志的时间要对上,时区不一致会多绕很大一圈。临时改动用注释写上日期和原因,过两周自己都记不清为什么这么写。
具体做法是,确认协程内部没有裸 except 吞掉取消异常,有就改成明确列出的类型;阻塞调用改成可取消的 await 点,别在协程里用同步 sleep 等待;超时后在 finally 里清理写了一半的状态,避免留下脏数据。
最后用这个标准收尾,超时后日志里不再出现该任务的新输出,数据库也没有留下半成品记录。
