使用 Flask 和 gunicorn 为服务器加载全局数据
Loading global data for server using Flask and gunicorn
我已经使用 Flask 框架实现了简单的 API,现在我正在尝试将它部署到 gunicorn 服务器。
我的服务器脚本如下所示:
app = Flask(__name__)
class Server(object):
def __init__(self, data):
self.data = data
@app.route("/api_method", methods=['GET', 'POST'])
def api_method():
return server.data
if __name__ == '__main__':
with smart_open(sys.argv[1]) as f:
server = Server(f.read())
app.run()
当我从控制台 运行 作为 "Flask app" 时一切正常,但是当我尝试在 gunicorn 下 运行 时它看不到服务器。我只能通过移动服务器创建来修复它,但我必须对路径进行硬编码。
有什么方法可以在 gunicorn 服务器启动时加载像我的服务器 class 这样的东西,然后在 API 方法中读取它吗?
这是我关于如何执行此操作的建议。
1. 如果需要以这种方式实例化,我不会依赖全局 server
变量。由于它是在应用程序创建后实例化的,因此最好以某种方式将其显式传递到应用程序中。这样你就可以从其他模块(blueprints, pluggable views等)访问它例如,你可以使用Flask的配置机制:
app.config['server'] = Server(f.read())
#...then in your view functions...
return app.config['server'].data
或者通过flask的globals object,g
:
@app.before_request
def add_server_to_globals():
with open(sys.argv[1]) as f:
g.server = Server(f.read())
#...then in your view functions...
return g.server.data
或者通过 subclassing Flask
并通过初始化器传递它。
2. 现在你正在使用 gunicorn,你不能依赖 if __name__ == '__main__'
块,因为它只在你 运行文件,而不是在导入时。 Gunicorn 通过导入应用程序对象(参见 how APP_MODULE is explained in the docs)并将其传递给 gunicorn 的 WSGI 服务器来工作,因此您用于实例化 Server
的代码不会 运行.
unicorn 的另一个新要求是您不能依赖 sys.argv
,因为这将是 gunicorn 的 sys.argv
,这与您当前在 [=62= 时传入的任何参数不同]直接打开文件。
要替换 if __name__ == '__main__'
块,您可以像我上面那样使用 before_request
来 运行 在应用程序处理其第一个请求之前的一些代码。我建议使用环境变量或 config file 将您的参数传递给 Server
class。例如:
@app.before_request
def add_server_to_globals():
with open(os.environ['SERVER_FILE']) as f:
g.server = Server(f.read())
然后 运行 您的应用程序设置了环境变量:
$ SERVER_FILE=blah.txt gunicorn app:app
[2015-02-24 10:10:20 -0800] [3217] [INFO] Starting gunicorn 19.2.1
...
3. 您还可以查看 flask 文档中描述的 "application factory" 模式来替换 if __name__ == '__main__'
块。但在这种情况下,它不是很有必要。如果您只想实例化 Server
对象一次(出于性能原因),则可以使用应用程序工厂。
简单:)
with smart_open(sys.argv[2]) as f:
server = Server(f.read())
if __name__ == '__main__':
app.run()
Steven Kryskalla 在他的回答中已经给出了逻辑。
但是请确保将 app.run()
保留在 if __name__=="__main__"
中,因为当 gunicorn 导入服务器 [= 时,您不希望它成为 运行 13=]
编辑:
实际上必须有 sys.argv[2],因为在 sys.argv[1] 中是服务器应用程序的路径。
我已经使用 Flask 框架实现了简单的 API,现在我正在尝试将它部署到 gunicorn 服务器。
我的服务器脚本如下所示:
app = Flask(__name__)
class Server(object):
def __init__(self, data):
self.data = data
@app.route("/api_method", methods=['GET', 'POST'])
def api_method():
return server.data
if __name__ == '__main__':
with smart_open(sys.argv[1]) as f:
server = Server(f.read())
app.run()
当我从控制台 运行 作为 "Flask app" 时一切正常,但是当我尝试在 gunicorn 下 运行 时它看不到服务器。我只能通过移动服务器创建来修复它,但我必须对路径进行硬编码。
有什么方法可以在 gunicorn 服务器启动时加载像我的服务器 class 这样的东西,然后在 API 方法中读取它吗?
这是我关于如何执行此操作的建议。
1. 如果需要以这种方式实例化,我不会依赖全局 server
变量。由于它是在应用程序创建后实例化的,因此最好以某种方式将其显式传递到应用程序中。这样你就可以从其他模块(blueprints, pluggable views等)访问它例如,你可以使用Flask的配置机制:
app.config['server'] = Server(f.read())
#...then in your view functions...
return app.config['server'].data
或者通过flask的globals object,g
:
@app.before_request
def add_server_to_globals():
with open(sys.argv[1]) as f:
g.server = Server(f.read())
#...then in your view functions...
return g.server.data
或者通过 subclassing Flask
并通过初始化器传递它。
2. 现在你正在使用 gunicorn,你不能依赖 if __name__ == '__main__'
块,因为它只在你 运行文件,而不是在导入时。 Gunicorn 通过导入应用程序对象(参见 how APP_MODULE is explained in the docs)并将其传递给 gunicorn 的 WSGI 服务器来工作,因此您用于实例化 Server
的代码不会 运行.
unicorn 的另一个新要求是您不能依赖 sys.argv
,因为这将是 gunicorn 的 sys.argv
,这与您当前在 [=62= 时传入的任何参数不同]直接打开文件。
要替换 if __name__ == '__main__'
块,您可以像我上面那样使用 before_request
来 运行 在应用程序处理其第一个请求之前的一些代码。我建议使用环境变量或 config file 将您的参数传递给 Server
class。例如:
@app.before_request
def add_server_to_globals():
with open(os.environ['SERVER_FILE']) as f:
g.server = Server(f.read())
然后 运行 您的应用程序设置了环境变量:
$ SERVER_FILE=blah.txt gunicorn app:app
[2015-02-24 10:10:20 -0800] [3217] [INFO] Starting gunicorn 19.2.1
...
3. 您还可以查看 flask 文档中描述的 "application factory" 模式来替换 if __name__ == '__main__'
块。但在这种情况下,它不是很有必要。如果您只想实例化 Server
对象一次(出于性能原因),则可以使用应用程序工厂。
简单:)
with smart_open(sys.argv[2]) as f:
server = Server(f.read())
if __name__ == '__main__':
app.run()
Steven Kryskalla 在他的回答中已经给出了逻辑。
但是请确保将 app.run()
保留在 if __name__=="__main__"
中,因为当 gunicorn 导入服务器 [= 时,您不希望它成为 运行 13=]
编辑: 实际上必须有 sys.argv[2],因为在 sys.argv[1] 中是服务器应用程序的路径。