在烧瓶应用程序启动后运行代码

时间:2014-12-14 01:40:08

标签: python flask flask-script

我的目标是在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装饰者。

6 个答案:

答案 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。 :(以我的观点)此解决方案的问题:调试难度更大。