Mod-wsgi重复调用Flask工厂函数的原因及解决办法
问题原因
mod_wsgi在默认的daemon进程模式下(mod_wsgi-express默认启用此模式),Apache主进程会先预加载WSGI模块做语法与有效性检查,随后实际处理请求的daemon进程会再次加载该模块。你的__init__.py在模块级别直接调用了create_app(),这部分代码会在模块加载时执行,因此两次加载就导致工厂函数被调用两次。从日志中同一PID的重复打印也能验证这是同一进程内模块重复加载引发的问题。
解决方案
以下三种方法可以解决该问题,按需选择:
1. 给工厂函数添加单例逻辑(最稳妥,不依赖服务器配置)
修改app.py,通过全局变量确保应用实例只初始化一次,后台线程也只会启动一次:
from flask import Flask import os # 全局变量存储已创建的应用实例 _app_instance = None def create_app(): global _app_instance # 已存在实例则直接返回,避免重复初始化 if _app_instance is not None: return _app_instance _app_instance = Flask('sample-app') print("inside factory function!") print(f"flask-env {os.environ['FLASK_ENV']}") # 在这里启动后台线程,只会执行一次 @_app_instance.route('/', methods=['GET']) def hello_world(): return "Hello! this is a sample flask app!" return _app_instance
2. 修改WSGI入口,延迟应用创建
调整__init__.py,让mod_wsgi直接调用工厂函数创建应用,而非在模块加载时就初始化:
from src.app import create_app def application(environ, start_response): app = create_app() return app(environ, start_response)
这种方式会让应用在第一次请求时才初始化,避免模块预加载阶段的重复调用。
3. 调整mod_wsgi-express启动参数
通过添加参数关闭主进程的预加载检查,避免模块重复加载:
修改Dockerfile中的启动命令,添加--disable-main-process-check参数:
CMD ["mod_wsgi-express", "start-server", "/sample-flask-app/src/__init__.py", "--user", "www-data", "--group", "www-data", "--port", "9090", "--disable-main-process-check"]
这个参数会禁止Apache主进程预加载WSGI模块,仅让daemon进程加载一次,从而避免工厂函数被两次调用。
内容的提问来源于stack exchange,提问作者Kevin123
相关产品推荐
相关产品推荐

