记一次 gunicorn 启动 flask 出问题的经历
出错现象:
gunicorn+nginx+flask 部署项目, 部署过程没问题,项目也正常启动了,但是一旦访问接口,就会报错:
Traceback (most recent call last):
File "/usr/local/lib/python3.6/dist-packages/gunicorn/workers/sync.py", line 135, in handle
self.handle_request(listener, req, client, addr)
File "/usr/local/lib/python3.6/dist-packages/gunicorn/workers/sync.py", line 176, in handle_request
respiter = self.wsgi(environ, resp.start_response)
TypeError: __call__() takes from 1 to 2 positional arguments but 3 were given
但是我通过 runserver运行的话,是没有问题的,外网可以正常访问.
所以问题就出在gunicorn 和 flask 的 wsgi 对接上.
gunicorn 启动时的方式是 gunicorn [options] file:app
我其他方面想了很多,试了很多,都没解决, 然后盯着这句话想了一二十分钟........ 嗯.......可能是这个原因:
直接通过终端 runserver方式启动的话,会直接运行启动文件, 最终提供服务的是app (就是flask的实例)
我为了数据库迁移, 启动文件注册了flask-script的对象,最后启动的实际是flask-script对象, 这个对象提供的就是些命令行之类的东西, 简单地说,就是一个命令行扩展, 在不使用命令行迁移数据库的时候没什么用(至少我小白看来是这样).
这就出来个想法了.
gunicorn说白了就是服务代理, 用来处理高并发的, 通过多进程/协程/线程 的方式提供并发访问, 所以gunicorn 代理的是flask对象, 也就是flask实例化的APP.
我的启动文件代码大概如下:
from projects import APP, db
from flask_migrate import Migrate, MigrateCommand
from flask_script import Manager manage = Manager(APP)
migrate = Migrate(app=APP, db=db)
manage.add_command('db', MigrateCommand) if __name__ == '__main__':
manage.run()
我这次的错误就在于将 flask-script的实例提供给了gunicorn, 这就导致了gunicorn接收到的参数并不是标准wsgi参数,所以报错.
解决办法很简单: 将APP(对于此处而言)交给gunicorn代理就好了.
所以gunicorn的启动命令改成:
gunicorn -D -w 3 -t 300 -b 0.0.0.0:5000 manage:APP
有需要的话,加上日志的配置,个人建议最好加上日志,日志是处理问题的最直接资料
gunicorn -D --error-logfile=/logs/gunicorn.log --pid=/logs/gunicorn.pid --access-logfile=/logs/access.log -w 3 -t 300 -b 0.0.0.0:5000 manage:APP
所以本次问题的原因在于wsgi协议未被标准的执行,代理服务器代理的是服务器APP, 而我一直没注意到这个.
下面是flask-script在终端直接runserver时的运行机制:
如我上方代码所示,manage是flask-script的实例, 执行Python manage时, 会执行该实例的run()方法
def run(self, commands=None, default_command=None):
"""
Prepares manager to receive command line input. Usually run
inside "if __name__ == "__main__" block in a Python script. :param commands: optional dict of commands. Appended to any commands
added using add_command(). :param default_command: name of default command to run if no
arguments passed.
""" if commands:
self._commands.update(commands) # Make sure all of this is Unicode
argv = list(text_type(arg) for arg in sys.argv)
if default_command is not None and len(argv) == 1:
argv.append(default_command) try:
result = self.handle(argv[0], argv[1:])
except SystemExit as e:
result = e.code sys.exit(result or 0)
如上方法会执行 handle() 然后通过一系列的方法,路过执行如下代码:
def add_default_commands(self):
"""
Adds the shell and runserver default commands. To override these,
simply add your own equivalents using add_command or decorators.
""" if "shell" not in self._commands:
self.add_command("shell", Shell())
if "runserver" not in self._commands:
self.add_command("runserver", Server())
上面的代码会给flask-script对象添加两个命令,其中就有我们很熟悉的 runserver, 该命令会执行Server()对象的call方法,call方法如下:
def __call__(self, app, host, port, use_debugger, use_reloader,
threaded, processes, passthrough_errors, ssl_crt, ssl_key):
# we don't need to run the server in request context
# so just run it directly if use_debugger is None:
use_debugger = app.debug
if use_debugger is None:
use_debugger = True
if sys.stderr.isatty():
print("Debugging is on. DANGER: Do not allow random users to connect to this server.", file=sys.stderr)
if use_reloader is None:
use_reloader = use_debugger if None in [ssl_crt, ssl_key]:
ssl_context = None
else:
ssl_context = (ssl_crt, ssl_key) app.run(host=host,
port=port,
debug=use_debugger,
use_debugger=use_debugger,
use_reloader=use_reloader,
threaded=threaded,
processes=processes,
passthrough_errors=passthrough_errors,
ssl_context=ssl_context,
**self.server_options)
到这里就很明了了,在执行 python manage.py runserver 的时候,如果命令不是flask-script的提供的其他命令的话,就会执行flask实例的run方法, 实质上,就是 Flask(__name__).run()
而flask-script就是监测有没有收到自己的命令.
虽然flask-script也会代理flask的APP, 但是flask-script的对象并不等同与flask的实例,所以提供给gunicorn的还必须得是flask的app
记一次 gunicorn 启动 flask 出问题的经历的更多相关文章
- gunicorn启动flask项目的坑
问题描述:项目用的是flask框架,在项目上线的时候,服务器上是使用gunicorn来启动项目的.但是上线之后,发现服务成功启动了,也有正确的返回值,但是没有生成日志,而用python来启动服务的时候 ...
- 用gunicorn+gevent启动Flask项目
转自:https://blog.csdn.net/dutsoft/article/details/51452598 Flask,webpy,Django都带着 WSGI server,当然性能都不好, ...
- web 部署专题(二):gunicore 并发部署(用gunicorn+gevent启动Flask项目)
转自:https://blog.csdn.net/dutsoft/article/details/51452598 Flask,webpy,Django都带着 WSGI server,当然性能都不好, ...
- gunicorn部署Flask服务
作为一个Python选手,工作中需要的一些服务接口一般会用Flask来开发. Flask非常容易上手,它自带的app.run(host="0.0.0.0", port=7001)用 ...
- 通过uwsgi+nginx启动flask的python web程序
通过uwsgi+nginx启动flask的python web程序 一般我们启动python web程序的时候都是通过python直接启动主文件,测试的时候是可以的,当访问量大的时候就会出问题pyth ...
- 【错误记录】uwsgi 启动 flask 出错
在测试环境使用uwsgi启动flask未成功 正常报错信息: *** Starting uWSGI 2.0.13.1 (64bit) on [Fri Sep 23 09:27:47 2016] *** ...
- Gunicorn+Nginx+Flask项目部署
安装python3.6 1)前往用户根目录 >: cd ~ 2)下载 或 上传 Python3.6.7 >: wget https://www.python.org/ftp/python/ ...
- Ubuntu16.04下搭建mysql + uwsgi + nginx环境启动flask 项目
1.安装mysql Sudo apt-get install mysql 配置mysql的数据存储路径,默认在 /var/lib/mysql sudo cp -R /var/lib/mysql/* / ...
- 记一次 mysql 启动没反应
记一次 mysql 启动没反应 ,重启linux又可以启动 vim /var/log/mysqld.log 2018-02-04 13:22:49 28507 [ERROR] InnoDB: Cann ...
随机推荐
- token与安全
http://ju.outofmemory.cn/entry/134189 关于 Token,你应该知道的十件事 https://blog.csdn.net/Fabulous1111/art ...
- linux 文件相关常用命令
文件或者目录操控命令 1,cd切换目录. 其中- 代表前一个目录 2,mkdir 新建目录. 加上-p参数可以递归创建多级目录 mkdir -p test1/test2/test3 3,rmdir删除 ...
- 把Vim改装成一个IDE编程环境
一:安装中文帮助手册 1. 打开一个终端 2.下载vimcdoc-1.5.0.tar.gz 下载地址: http://nchc.dl.sourceforge.net/source ...
- PROD异机全备份恢复验证实施文档
PROD异机全备份恢复验证实施文档 ******利用10月25日的全量备份.10月26日当天的归档日志及当前redo日志,恢复数据库到故障前数据库状态****** 准备工作:source 源库:PRO ...
- Gradle 编译加速
参考:http://www.jianshu.com/p/200d55b4d40a http://blog.isming.me/2015/03/18/android-build-speed-up/ ht ...
- 如何把一些字符串用dict组织成json格式?(小算法)
说明: 1. 数据库中的一条记录取出来是这样的(直接复制):'value1','value2' ,'value3' 2. 我希望使用的数据格式是:{key1:'value1',key2:'value2 ...
- 20160419—JS备忘:服务器回发刷新页面提示重试的解决方案。
有事页面刷新时 提示如下: js使用的是:location.reload()的刷新方式. 使用js重新定向该页面:location.href="a.aspx"; 当使用:self. ...
- 阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_02 递归_1_递归概念&分类&注意事项
a方法里面调用自己,但是没有停止的条件 方法没有停止的条件. 栈内存溢出的异常. 只有栈,没有堆内存 先执行main方法压栈执行 main方法里面调用a方法.a方法就会压栈 改成20000
- 《图解设计模式》读书笔记7-1 facade模式
目录 1. Facade模式简介 2. 示例程序 2.1 类图 2.2 程序 3.角色和类图 4.思路拓展 1. Facade模式简介 开发程序的过程中,随着时间的推移,类会越来越多,调用关系会越来越 ...
- postman+newman+jenkins接口自动化
postman用来做接口测试非常方便,接口较多时,则可以实现接口自动化 目录 1.环境准备 2.本机调试脚本 3.集成jenkins 1.环境准备 1.1安装nodejs6.0+ 安装nodejs6. ...