Sanic框架before/after_server_stop监听器失效问题求助
问题:Sanic服务器停止时
before_server_stop和after_server_stop监听器未触发 运行以下代码时,按下Ctrl+C停止服务器,before_server_stop和after_server_stop两个监听器未生效,控制台仅输出启动日志:
from loguru import logger from sanic import Sanic app = Sanic(__name__) @app.before_server_start async def start(*_): logger.info("Server starting...") @app.before_server_stop async def before_server_stop(*_): logger.info("Server stopping...") @app.after_server_stop async def after_stop(app, loop): logger.info("Server shutting down...") @app.route("/") async def test(request): return text("test") if __name__ == '__main__': try: app.run(host='0.0.0.0', port=8000, workers=1) except KeyboardInterrupt: app.stop()
控制台输出:
2024-09-10 16:45:23.567 | INFO | __mp_main__:start:20 - Server starting...
解决方法
1. 修复缺失的text函数导入
原代码中调用text("test")但未导入该函数,会导致请求时报错,先补上导入语句:
from sanic.response import text
2. 调整服务器停止的处理逻辑
当指定workers=1时,Sanic会启动多进程模式(主进程+1个worker进程),此时主进程捕获KeyboardInterrupt后调用的app.stop()无法触发worker进程上注册的监听器——因为监听器属于worker进程的app实例,和主进程的app实例是分离的。
有两种可行的修复方式:
方式一:使用单进程模式
去掉workers参数(默认单进程),或者显式指定single_process=True,让服务器运行在单个进程中:
if __name__ == '__main__': app.run(host='0.0.0.0', port=8000)
此时按下Ctrl+C,监听器会正常触发,控制台会输出:
2024-09-10 16:45:23.567 | INFO | __main__:start:20 - Server starting... 2024-09-10 16:46:00.123 | INFO | __main__:before_server_stop:24 - Server stopping... 2024-09-10 16:46:00.124 | INFO | __main__:after_stop:28 - Server shutting down...
方式二:多进程模式下移除手动停止逻辑
如果必须使用多进程,直接移除主进程的try-except块,让Sanic自身处理停止流程——Sanic会自动向所有worker进程发送停止信号,触发对应的监听器:
if __name__ == '__main__': app.run(host='0.0.0.0', port=8000, workers=1)
3. 确认监听器参数正确性
before_server_stop的标准参数签名是async def before_server_stop(app, loop),你的代码中用*_忽略参数是可行的,但如果后续需要使用app或loop对象,需确保正确接收参数。
内容的提问来源于stack exchange,提问作者hpp
相关产品推荐
相关产品推荐

