Sanic服务启动失败,记录解决方法
问题描述
Sanic服务启动失败,同样的代码和python版本在之前的win10系统上运行的好好的,换了台win11的机器就跑不起来了,不知道是系统原因还是因为换了执行pycharm等其他原因
在尝试启动时总是会报类似如下的错误:
…
sanic_routing.exceptions.FinalizationError: Cannot finalize with no routes defined.
sys:1: RuntimeWarning: coroutine ‘BaseEventLoop.create_server’ was never awaited
…
报错部分截图:
运行环境:
- win11
- pycharm
- python3.9
运行方式:
- debug方式或普通右键方式运行
尝试找到原因并解决
发现的表象原因:
sanic服务注册路由时放在了函数中执行会导致路由在app启动时还没有注册,从而导致启动失败
sanic关闭服务时也会检测是否注册路由,如果没有路由就会报上面提到的错误:Cannot finalize with no routes defined.
例如下图中的
# -*- coding:utf-8 -*-
from sanic import response, Sanic
from sanic.views import HTTPMethodViewapp = Sanic("abc")class NameTest(HTTPMethodView):@classmethodasync def post(cls, request):print(cls.post.__name__)return response.text("test")def register_route():# 注册路由放到了方法中,如果用这种方式,会导致启动失败app.add_route(NameTest.as_view(), "/test")if __name__ == '__main__':register_route()app.run()
可以正确启动的方式:
是把注册路由相关的方法(blueprint、add_router这些)放到app所在的全局处理:
# -*- coding:utf-8 -*-
from sanic import response, Sanic
from sanic.views import HTTPMethodViewapp = Sanic("abc")class NameTest(HTTPMethodView):@classmethodasync def post(cls, request):print(cls.post.__name__)return response.text("test")# 注册路由放在了全局执行
app.add_route(NameTest.as_view(), "/test")if __name__ == '__main__':app.run()
找到了表象原因,代码不多可以通过将注册路由的时机放到全局启动时来解决这个问题
但是如果是在工作项目中,已经写好了大部分的的路由注册方式(而且大概率会在方法中执行路由注册)
更新,根本原因及解决方法
在sanic github的一个issue找到的部分原因和线索:
对app的任何操作(例如,注册路由/创建蓝图/更新配置等)都必须在if __name__ == '__main__'
之前完成,在if __name__ == '__main__'
对app的操作只能时app.run
因此解决办法就是把app.run的其他操作都在if __name__ == '__main__'
之前做完即可
例如,在if __name__ == '__main__'
之前先运行路由注册
# -*- coding:utf-8 -*-
# -*- coding:utf-8 -*-
from sanic import response, Sanic
from sanic.views import HTTPMethodViewapp = Sanic("abc")class NameTest(HTTPMethodView):@classmethodasync def post(cls, request):print(cls.post.__name__)return response.text("test")def register_route():app.add_route(NameTest.as_view(), "/test")register_route()if __name__ == '__main__':app.run()