在 Flask 应用开发中,使用工厂函数创建应用实例,并借助 uWSGI 服务进行部署,是常见且高效的组合。

然而,在实际操作过程中,uWSGI 配置文件与应用启动函数之间的关系复杂,容易引发各种问题。

本文将详细探讨其中的关键要点和注意事项,帮助开发者顺利完成 Flask 应用的部署。

一、Flask 应用工厂函数简介

Flask 应用工厂函数是一种创建 Flask 应用实例的设计模式。通过将应用的创建逻辑封装在函数中,我们可以实现更灵活的配置和复用。例如:

from flask import Flask

# 创建Flask应用
def create_app():
app = Flask(__name__)
# 加载配置
app.config.from_object('config.Config')
# 初始化扩展
from models import db
db.init_app(app)
# 注册蓝图
from api import register_blueprints
register_blueprints(app) @app.route('/')
def index():
return "Hello, Flask!" return app if __name__ == '__main__':
app = create_app()
app.run()

在上述代码中,create_app函数负责创建 Flask 应用实例,配置应用,初始化数据库,并注册蓝图。这种方式使得应用的创建和配置分离,便于管理和维护。

二、uWSGI 配置文件详解

uWSGI 是一个高性能的 Web 服务器,支持多种协议和功能。在部署 Flask 应用时,需要正确配置 uWSGI 配置文件(通常为.ini格式)。以下是一个典型的 uWSGI 配置文件示例:

[uwsgi]
# 项目根目录
chdir = /home/flask_pro
# 应用模块和可调用对象
module = app:create_app
callable = app
# 进程和线程设置
master = true
processes = 4
threads = 2
# 网络设置
socket = 127.0.0.1:5000
# 其他设置
vacuum = true
harakiri = 60
pidfile = uwsgi.pid
daemonize = uwsgi.log
  1. chdir:指定项目的根目录,uWSGI 会在该目录下查找应用模块。
  2. module:指定要加载的应用模块和可调用对象。格式为<模块名>:<可调用对象>,这里的app是包含create_app函数的 Python 模块名,create_app是创建 Flask 应用实例的函数。
  3. callable:指定module中返回的可调用对象,即 Flask 应用实例。在上述示例中,create_app函数返回的 Flask 应用实例名为app
  4. master:设置为true时,uWSGI 会启动一个主进程来管理子进程,提高稳定性。
  5. processesthreads:分别设置 uWSGI 的进程数和每个进程的线程数,用于控制应用的并发处理能力。
  6. socket:指定 uWSGI 监听的 IP 地址和端口号,用于接收外部请求。
  7. vacuum:设置为true时,uWSGI 在退出时会自动清理环境,如删除临时文件。
  8. harakiri:设置请求的超时时间,单位为秒。
  9. pidfiledaemonize:分别指定 uWSGI 进程 ID 文件和日志文件的路径,用于记录进程信息和日志。

三、uWSGI 配置文件与 app 启动函数的关系

  1. 入口函数的匹配:uWSGI 通过modulecallable配置来定位 Flask 应用的入口函数。module指定包含应用创建逻辑的模块,callable指定模块中返回 Flask 应用实例的函数或对象。在使用工厂函数创建应用时,callable通常是工厂函数返回的应用实例。
  2. 参数传递问题:在配置 uWSGI 时,容易混淆应用创建函数和 WSGI 应用接口。WSGI 规范要求应用入口函数接受environstart_response两个参数,但 Flask 应用工厂函数通常不需要这两个参数。如果在工厂函数中错误地添加了这两个参数,可能会导致 “TypeError: 'Flask' object is not iterable” 错误。因为工厂函数返回的 Flask 应用实例本身不是可迭代的,而 WSGI 期望的是一个可迭代对象来生成响应内容。正确的做法是,在工厂函数中返回 Flask 应用实例,然后通过 uWSGI 的配置来正确调用应用。
  3. 应用配置与环境变量:uWSGI 配置文件中的chdir和 Flask 应用工厂函数中的配置加载逻辑密切相关。chdir指定的项目根目录决定了 Flask 应用查找配置文件、静态文件和模板文件的路径。在工厂函数中,通常会使用app.config.from_object方法加载配置,配置文件的路径和名称应与项目结构和 uWSGI 配置相匹配。此外,还可以通过环境变量来传递配置信息,提高应用的灵活性和可扩展性。

四、部署过程中的问题及解决方法

通常根据网上经验,按照根据上面的app代码和uWSGI配置文件部署应该没有问题,但是实际部署到服务器上,启动后发现app并没有正确启动成功,日志显示报错如下:

错误信息 “TypeError: create_app() takes 0 positional arguments but 2 were given”

表示 create_app() 函数被调用时传入了两个位置参数,但该函数不接受任何位置参数。

在 uWSGI 中,如果 callable 参数指定的函数不接受任何参数,那么在配置文件中就不应该提供任何额外的参数。

uWSGI 默认会将 environ 和 start_response 两个参数传递给 WSGI 应用程序。这可能是导致错误的原因。

[INFO] bound built-in connection pool when new client. maxsize=10,10
WSGI app 0 (mountpoint='') ready in 4 seconds on interpreter 0x26ced20 pid: 3592 (default app)
*** uWSGI is running in multiple interpreter mode ***
spawned uWSGI master process (pid: 3592)
spawned uWSGI worker 1 (pid: 3595, cores: 2)
spawned uWSGI worker 2 (pid: 3596, cores: 2)
spawned uWSGI worker 3 (pid: 3597, cores: 2)
spawned uWSGI worker 4 (pid: 3598, cores: 2)
TypeError: create_app() takes 0 positional arguments but 2 were given

然而不是随便将将 environ 和 start_response 两个参数加入到create_app(environ,start_response)函数中的,这样修改,使用uWSGI启动后,又会出现新的报错:

“TypeError: 'Flask' object is not iterable” 错误。

因为工厂函数返回的 Flask 应用实例本身不是可迭代的,而 WSGI 期望的是一个可迭代对象来生成响应内容。

经过查询网上资料以及多个AI平台分析问题,多次测试验证,最终解决方案如下:

1、修改flask应用启动代码:

  增加一个符合 WSGI 规范的应用入口函数。

from flask import Flask

# 创建Flask应用
def create_app():
print("开始创建Flask应用...")
app = Flask(__name__)
# 加载配置
app.config.from_object('config.Config')
# 初始化扩展
from models import db
db.init_app(app)
# 注册蓝图
from api import register_blueprints
register_blueprints(app) @app.route('/')
def index():
return "Hello, Flask!" return app # 定义一个符合 WSGI 规范的应用入口函数
def application(environ, start_response):
app = create_app()
return app.wsgi_app(environ, start_response) if __name__ == '__main__':
app = create_app()
app.run()

2、修改uWSGI 配置文件:

  修改 module:指定要加载的应用模块和可调用对象。格式为<模块名>:<可调用对象>。

  修改 callable:指定module中返回的可调用对象。

[uwsgi]
# 这里是你的项目根目录路径
chdir = /home/项目根目录路径
# 模块名,这里用 app;app:application 是指定一个 Python 的可执行文件,它包括符合 WSGI 规范的代码
module = app:application
# 因为 application 是启动整个服务的入口,所以是 application
callable = application
# ... 其他配置不变 ...

3、使用uWSGI启动app:

================uwsgi==========================
# 启动 uwsgi 命令
cd /home/flask_pro # 项目文件夹,uwsgi.ini 配置文件 下执行
uwsgi --ini uwsgi.ini
# 停止 uwsgi 命令
uwsgi --stop uwsgi.pid
# 查端是否启动成功
ps -ef|grep uwsgi
================uwsgi==========================

  启动成功,打开网址验证下你的服务接口。

[INFO] generate built-in connection pool success. maxsize=10,10
[INFO] bound built-in connection pool when new client. maxsize=10,10
[INFO] bound built-in connection pool when new client. maxsize=10,10
[INFO] bound built-in connection pool when new client. maxsize=10,10
[INFO] bound built-in connection pool when new client. maxsize=10,10
[INFO] bound built-in connection pool when new client. maxsize=10,10
WSGI app 0 (mountpoint='') ready in 1 seconds on interpreter 0x2656cf0 pid: 3772 (default app)
*** uWSGI is running in multiple interpreter mode ***
spawned uWSGI master process (pid: 3772)
spawned uWSGI worker 1 (pid: 3775, cores: 2)
spawned uWSGI worker 2 (pid: 3776, cores: 2)
spawned uWSGI worker 3 (pid: 3777, cores: 2)
spawned uWSGI worker 4 (pid: 3778, cores: 2)
开始创建Flask应用...

五、总结

在 Flask 应用开发中,使用工厂函数创建应用实例并结合 uWSGI 进行部署,可以提高应用的灵活性、可维护性和性能。

在配置 uWSGI 时,需要特别注意配置文件与应用启动函数之间的关系,确保正确指定应用入口函数、处理参数传递问题,并合理设置进程、线程和网络参数。

同时,通过查看日志和解决常见问题,可以快速完成应用的部署和调试。希望本文对您在 Flask 应用部署方面有所帮助,祝您开发顺利!

如果你觉得文章内容对你有所启发,不妨点赞、关注支持一下。要是你在实际操作中遇到了不一样的情况,或是有独特的见解和经验,欢迎在评论区分享交流,大家共同进步。

Flask应用实战经验总结:使用工厂函数创建app与uWSGI服务部署启动失败解决方案的更多相关文章

  1. flask实战-个人博客-使用工厂函数创建程序实例 --

    使用工厂函数创建程序实例 使用蓝本还有一个重要的好处,那就是允许使用工厂函数来创建程序实例.在OOP(Object-Oriented Programming,面向对象编程)中,工厂(factory)是 ...

  2. 【flask】使用类组织配置-使用工厂函数创建程序实例

    [需求] 使用配置类管理flask管理测试环境, 通过1个参数即可控制Flask是运行develpment环境还是production环境(数据库配置,邮件配置也要根据环境的变化而变化) [思路] 1 ...

  3. Mysql启动失败解决方案 - 个人经验可能不适合所有场景

    以前一直用的Mysql5.5,安装程序是一个exe程序,安装完了相应的服务也给我注册好了,然后直接启动连接即可. 最近升级到了8.0.15,发现和以前不一样了. 8.0.15下载地址 安装解压之后目录 ...

  4. JavaScript中的构造函数和工厂函数说明

    在cnblog上看到一篇文章,讲解JS中的构造函数和工厂函数,觉得讲的真好 JavaScript中的工厂函数和构造函数都能用来创建一个对象,我们可以来看看下面的例子 构造函数 function cre ...

  5. js工厂函数创建对象与对象构造函数的理解

    工厂函数,顾名思义,就是通过一个"工厂的加工" 来创建一个对象的函数 //工厂函数 function createPerson(name,sex){ sex = sex == '男' ? '女' : ...

  6. 为什么要使用Redis? —— Redis实战经验

    (序言,从一张思维导图开始,慢慢介绍我自己关于Redis的实战经验) 现在很多互联网应用的服务端都使用到了Redis,到底大家为什么要用Redis呢?Redis有很多特性,比如高性能.高可用.数据类型 ...

  7. Flask:工厂函数和蓝本

    我们用pycharm去新建Flask项目的时候,会默认生成开发文件.如下,其中包括static,templates,flask1_prj.py文件 在最初开始的时候,我们的app等声明都是在flask ...

  8. MySQL数据库的优化-运维架构师必会高薪技能,笔者近六年来一线城市工作实战经验

    原文地址:http://liangweilinux.blog.51cto.com/8340258/1728131 首先在此感谢下我的老师年一线实战经验,我当然不能和我的老师平起平坐,得到老师三分之一的 ...

  9. MySQL索引实战经验总结

    MySQL索引对数据检索的性能至关重要,盲目的增加索引不仅不能带来性能的提升,反而会消耗更多的额外资源,本篇总结了一些MySQL索引实战经验. 索引是用于快速查找记录的一种数据结构.索引就像是数据库中 ...

  10. Jenkins高级用法 - Jenkinsfile 介绍及实战经验

    系列目录 1.Jenkins 安装 2.Jenkins 集群 3.Jenkins 持续集成 - ASP.NET Core 持续集成(Docker&自由风格&Jenkinsfile) 4 ...

随机推荐

  1. UML之关联

    关联指两个类之间的各种联系.UML使用各种单实线表示关联,这个单实线可以是直线(垂直的.水平的或者倾斜的).折线甚至曲线. 事实上,关联也是展示类的属性的另一外的一种形式.例如在下图中,我们通过一条实 ...

  2. 在CLion中如何为CMakeLists.txt文件添加第三方依赖库

    cmake_minimum_required(VERSION 3.5)project(ImageBasedModellingEdu)set(CMAKE_MODULE_PATH "${CMAK ...

  3. v-for和v-if一起使用时的坑:The 'XXX' expression inside 'v-for' directive should be replaced with a computed property that returns filtered array instead. You should not mix 'v-for' with 'v-if'

    目的:Vue - ElementUI中循环渲染表格,控制字段的显示与隐藏 v-if与v-for同时使用. 在Vue中使用v-for循环一个数组/对象时,如果再使用v-if,那么会提示使用计算属性(能正 ...

  4. 史上最通俗Netty入门长文:基本介绍、环境搭建、动手实战

    原作者江成军,原题"还在被Java NIO虐?该试试Netty了",收录时有修订和改动. 1.阅读对象 本文适合对Netty一无所知的Java NIO网络编程新手阅读,为了做到这一 ...

  5. Omnivore 替代品 Readeck 安装与使用教程

    前段时间 Omnivore 宣布服务关停,作为一个长期使用 Omnivore 的用户,我需要寻找替代方案. 我对替代品的核心需求是: 浏览器插件:支持一键剪藏当前网页. RSS 支持:能够输入 RSS ...

  6. C 2017笔试题

    1.下面程序的输出结果是 int x=3; do { printf("%d\n",x-=2); }while(!(--x)); 输出:1 -2 解析:x初始值为3,第一次循环中运行 ...

  7. C++:异常处理

    C++的异常处理机制是由三部分组成:检查(try).抛出(throw)和捕获(catch).需要检查的语句放到try中:throw用来当出现异常时发出一个异常信息:catch用来捕获异常信息,且处理它 ...

  8. HElib

    什么是HElib? HElib是一个基于C++语言的同态加密开源软件库,底层依赖于NTL数论运算库和GMP多精度运算库实现,主要开发者为IBM的Halevi,目前最新版本为1.0.2,实现了支持&qu ...

  9. ABC243

    ABC224 D 题目大意 有一个九个点的无向图棋盘,上面有八个棋子,一次操作能将一个棋子沿边移到空点上,问将每个棋子移到与它编号相同的点最少几步. 解题思路 考虑使用 BFS. 用 string 存 ...

  10. 二叉树神级遍历算法:morris遍历算法

    morris遍历的实质 建立一种机制,对于没有左子树的节点只到达一次,对于有左子树的节点会到达两次 morris遍历的实现原则 记作当前节点为cur. 如果cur无左孩子,cur向右移动(cur=cu ...