我的目标是在Flask应用程序启动后运行任意代码。这就是我所拥有的:
def run():
from webapp import app
app.run(debug=True, use_reloader=False)
理想情况下,我可以这样做:
def run():
from webapp import app
app.run(debug=True, use_reloader=False)
some_code()
但代码不会继续app.run()
,因此some_code()永远不会运行。
我目前正在处理的解决方案是在app.run()的单独线程中运行some_code(),创建一个before first request函数来设置:
app.is_running = True
然后获取some_code()以向app发送基本请求,以便在第一次请求之前发出'代码运行。这相当复杂,难以记录。我宁愿使用已经在Flask中提供的app.is_running参数,也可以使用@app.after_server_start
装饰器,但据我所知,这些都不存在。
帮我改进一下这段代码吗?
Posthumous:每当我想到这个问题时,我都希望有一个@app.after_server_start
装饰者。
答案 0 :(得分:22)
如果您需要在烧瓶应用程序启动后执行某些代码,但严格在第一个请求之前执行,甚至不能执行@ app.before_first_request可以处理的第一个请求,您应该使用Flask_Script,如CESCO所说,但你可以继承类Server并覆盖__ call __方法,而不是用@ manager.command覆盖runserver命令:
from flask import Flask
from flask_script import Manager, Server
def custom_call():
#Your code
pass
class CustomServer(Server):
def __call__(self, app, *args, **kwargs):
custom_call()
#Hint: Here you could manipulate app
return Server.__call__(self, app, *args, **kwargs)
app = Flask(__name__)
manager = Manager(app)
# Remeber to add the command to your Manager instance
manager.add_command('runserver', CustomServer())
if __name__ == "__main__":
manager.run()
这样您就不会覆盖runserver命令的默认选项。
答案 1 :(得分:9)
使用Flask-Script运行您的应用,然后像这样覆盖runserver类/方法
# manage.py
from flask.ext.script import Manager
from myapp import app
manager = Manager(app)
def crazy_call():
print("crazy_call")
@manager.command
def runserver():
app.run()
crazy_call()
if __name__ == "__main__":
manager.run()
答案 2 :(得分:0)
我在我的烧瓶应用程序中遇到了同样的问题。我想在应用启动时启动一个调度程序,该调度程序会定期启动一些作业。由于我将应用程序部署在Docker容器中,因此最终要做的是添加一个“运行状况检查”端点,该端点仅返回200,并在我的dockerfile中配置了该端点:
HEALTHCHECK CMD curl --fail http://localhost:8080/alive || exit 1
默认行为是每30秒执行一次该命令,第一次运行方便地启动了我的init()方法。 https://docs.docker.com/engine/reference/builder/#healthcheck
答案 3 :(得分:0)
我刚刚做过(在main.py
执行的python main.py
中):
with app.app_context():
from module import some_code()
some_code()
def run():
from webapp import app
app.run(debug=True, use_reloader=False)
这对我有用,但没有上面提供的更全面的答案。在我的情况下,some_code()
正在通过flask_caching.Cache
初始化缓存。
但这可能取决于some_code
到底在做什么...
答案 4 :(得分:0)
我真的不喜欢上面提到的任何方法,因为您不需要Flask-Script来执行此操作,并且并非所有项目都已经在使用Flask-Script。
最简单的方法是建立自己的Flask子类。使用Flask(__name__)
构建应用的地方,只需添加自己的类并使用它即可。
def do_something():
print('MyFlaskApp is starting up!')
class MyFlaskApp(Flask):
def run(self, host=None, port=None, debug=None, load_dotenv=True, **options):
if not self.debug or os.getenv('WERKZEUG_RUN_MAIN') == 'true':
with self.app_context():
do_something()
super(MyFlaskApp, self).run(host=host, port=port, debug=debug, load_dotenv=load_dotenv, **options)
app = MyFlaskApp(__name__)
app.run()
当然,它不会在之后开始运行,但是恰好在之前 run()
被调用。使用应用程序上下文,您应该能够执行数据库可能需要做的任何事情,或者需要应用程序上下文的其他任何事情。这也适用于任何服务器(uwsgi,gunicorn等)。
如果您需要do_something()
成为非阻塞对象,则可以简单地用threading.Thread(target=do_something).start()
对其进行线程化。
条件语句是为了防止在使用调试模式/重新加载器时出现两次调用。
答案 5 :(得分:0)
如果您希望在烧瓶运行后运行一堆命令(作为常规Py应用程序),请使用多处理库(例如multiprocessing),在此解决方案中,您可以在旁边有一个API / Web应用程序系统程序。
import flask
from flask import request, jsonify,make_response
import time
import multiprocessing
app = flask.Flask('__name__')
def API(Conf):
print('In API selction')
app.run(host='0.0.0.0', port=1337,)
if __name__ == "__main__":
config = {"Something":"SomethingElese"}
p = multiprocessing.Process(target=API, args=(Conf,))
p.start()
#time.sleep(3)
print('After Flask run')
注意:上面的代码只是一个示例/想法。可能有一些错误。 (但是我在生产区域使用了此解决方案,这很好。)
P.S。 :(以我的观点)此解决方案的问题:调试难度更大。