使用CherryPy/Cherryd启动多个Flask实例

11 投票
2 回答
2830 浏览
提问于 2025-04-16 17:31

根据在StackOverflow和其他网站上的建议,我正在使用CherryPy作为WSGI服务器来启动我用Flask构建的多个Python网络服务器实例。每个实例都在自己的端口上运行,并且在Nginx后面。我想说明的是,下面的配置对我来说是有效的,但我有点担心我这样做可能是错误的,可能是“偶然”成功的。

这是我当前的cherrypy.conf文件:

[global]
server.socket_host = '0.0.0.0'
server.socket_port = 8891
request.dispatch: cherrypy.dispatch.MethodDispatcher()
tree.mount = {'/':my_flask_server.app}

不深入讲解我的Flask服务器,这里是它的启动方式:

import flask
app = flask.Flask(__name__)

@app.route('/')
def hello_world():
    return "hello"

这是我在命令行中发出的命令,用于通过Cherryd启动:

cherryd -c cherrypy.conf -i my_flask_server

我的问题是:

  1. 把Flask放在CherryPy里面,这还是在生产环境中使用Flask的推荐方法吗? https://stackoverflow.com/questions/4884541/cherrypy-vs-flask-werkzeug

  2. 使用.conf文件来启动CherryPy并导入Flask应用,这样做是正确的吗?我查阅了CherryPy的文档,但找不到与我想做的事情完全匹配的用例。

  3. 在一台机器上启动多个CherryPy/Flask实例的正确方法是执行多个cherryd命令(使用-d进行守护进程化等),并为每个要使用的端口(8891、8892等)准备独特的.conf文件吗?还是有更好的“CherryPy”方法来实现这个目标?

感谢任何帮助和见解。

2 个回答

3

术语:挂载与嫁接

原则上,通过 CherryPy 来提供 Flask 应用是正确的做法,不过我想简单说一下你的命名:

需要注意的是,tree.mount 本身并不是一个配置键——tree 会导致 cherrypy._cpconfig._tree_config_handler(k, v) 被调用,参数是 'mount', {'/': my_flask_server.app}

这里的关键参数在 _tree_config_handler 中根本没有被使用,所以在你的配置中,“mount”只是一个随便的标签,用来表示这个特定的路径映射字典。它也并没有真正“挂载”应用(毕竟这不是一个 CherryPy 应用)。我的意思是,它并不是通过 cherrypy.tree.mount(…) 来挂载,而是通过 cherrypy.tree.graft 将一个随便的 WSGI 处理器嫁接到你的“脚本名称”(在 CherryPy 的术语中是路径)命名空间上。

CherryPy 的日志信息有点误导地说“已在 / 上挂载 <app as string>”

这是一个比较重要的点,因为使用嫁接(graft)时,与挂载(mount)不同,你不能为你的应用或该路径上的流式响应指定更多选项,比如静态文件服务。

所以我建议把 tree.mount 的配置键改成一些更具描述性的名称,这样就不会让人误解 CherryPy 内部发生了什么(因为确实有 cherrypy.tree.mount 方法)。例如,如果你只是想在这个字典中映射一个应用,可以用 tree.flask_app_name(可以有很多 tree 指令,所有指令都会合并到路径命名空间中),或者如果你在这个字典中映射多个应用,可以用 tree.wsgi_delegates

使用 CherryPy 提供额外内容,而不需要创建应用

另外,如果你想让 CherryPy 提供静态文件服务,你并不需要创建一个模板 CherryPy 应用来保存这个配置。你只需要用适当的额外配置挂载 None。以下文件就足够让 CherryPy 从子目录 'static' 提供静态内容,只要把它们放到你启动 cherryd 的目录中(用 cherryd -c cherrypy.conf -i my_flask_server -i static 启动):

static.py

import cherrypy
# next line could also have config as an inline dict, but
# file config is often easier to handle
cherrypy.tree.mount(None, '/static-path', 'static.conf')

static.conf

# static.conf
[/]
tools.staticdir.on = True
tools.staticdir.root = os.getcwd()
tools.staticdir.dir = 'static'
tools.staticdir.index = 'index.html'
5

我不能代表Flask说话,但我可以说说CherryPy。看起来那是“正确的方式”……大部分情况下。关于MethodDispatcher的那一行其实没什么用,因为它只影响CherryPy应用,而你似乎没有挂载任何应用(只是一个Flask应用而已)。

关于第三点,你说得对。CherryPy允许你在同一个进程中运行多个服务器对象,这样可以监听多个端口(或者协议),但它并没有提供启动多个进程的简单方法。正如你所说,使用多个cherryd命令并配上不同的配置文件就是这样做的方式(除非你想用更集成的集群/配置管理工具,比如eggmonster)。

撰写回答