You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在aiohttp协程中正确处理服务优雅关闭?

关于该实现方案的评估

你的核心思路方向是对的,但直接按你描述的方式裸写有不少容易踩的坑,补全几个关键处理后才能稳定达到预期效果,具体问题和修正方案如下:

  • 不要用模块级全局数组存任务,最好把任务集合绑定到aiohttp的app实例上。全局变量在多实例测试、服务热重载场景下很容易出现任务串扰、内存泄漏问题,在startup生命周期回调里初始化app['persist_tasks'] = set()来存任务,生命周期和服务实例完全绑定,可控性高很多。
  • 直接调用await asyncio.gather(*global_jobs)有两个致命问题:
    1. 没有处理默认的任务取消逻辑:aiohttp触发shutdown流程时,默认会先取消所有未被显式持有、未做屏蔽的后台任务,等你走到shutdown回调执行gather的时候,很多存库任务可能已经被抛出CancelledError中断了,根本等不到执行完成。注册任务时要用asyncio.create_task()显式创建Task对象存入集合,必要时给核心存库逻辑包asyncio.shield()避免被提前取消。
    2. 没有异常和超时兜底:gather默认只要有一个任务抛出异常就会整体中断,万一某个存库协程因为数据库连接异常卡死、抛错,整个关闭流程要么直接挂死退不出去,要么打断其他正常执行的存库任务。调用gather时必须加return_exceptions=True参数,再外层套asyncio.wait_for设置合理超时(比如10秒),超时就强制结束剩余任务,别阻塞进程退出。
  • 不要把所有后台任务都放进等待列表,只有带状态持久化逻辑的收尾任务需要等待执行完成。那些长期跑循环的消费任务、定时拉取类任务,要在shutdown的最早期主动发取消信号等它们退出,别占着事件循环资源阻塞存库操作。
  • 注意生命周期回调的注册顺序:数据库连接池的销毁逻辑不要放在on_shutdown阶段,要绑定到on_cleanup信号上。aiohttp会先执行完所有on_shutdown回调,再执行on_cleanup回调做资源销毁,保证你在等待存库任务完成的时候,数据库连接是可用的,不会出现连不上库的问题。

最小可用实现参考

from aiohttp import web
import asyncio

async def on_startup(app: web.Application):
    # 初始化持久化任务集合
    app["persist_tasks"] = set()

async def add_persist_task(app: web.Application, coro):
    # 统一封装任务注册逻辑
    task = asyncio.create_task(coro)
    app["persist_tasks"].add(task)
    # 任务执行完成后自动从集合移除,避免内存泄漏
    task.add_done_callback(app["persist_tasks"].discard)
    return task

async def on_shutdown(app: web.Application):
    tasks = app["persist_tasks"]
    if not tasks:
        return
    # 最多等待10秒,捕获所有异常不中断关闭流程
    await asyncio.wait_for(
        asyncio.gather(*tasks, return_exceptions=True),
        timeout=10
    )

# 初始化服务时按顺序注册回调
app = web.Application()
app.on_startup.append(on_startup)
# 注意shutdown回调要放在cleanup回调前注册
app.on_shutdown.append(on_shutdown)
# 数据库连接池的初始化、销毁逻辑分别绑定到startup和cleanup信号即可

如果你用gunicorn这类多进程工具部署aiohttp服务,还要注意确认终止信号的处理逻辑,确保worker进程收到SIGTERM时能正常走完shutdown流程,不要被操作系统强杀导致状态丢失。

内容的提问来源于stack exchange,提问作者comonadd

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 14:54:37