Flask 如何实现 auto reloader

简介

对于长时间执行的任务,我们不可能将其放在一个请求中完成,通常会用其他的方式异步执行。 队列则就是这样一个专门提供非阻塞任务执行的系统组件。在开发过程中我需要对其异步执行的任务进行测试,由于Celery没有提供Inprocess的API,所以不能直接在测试、开发的时候调用需要一番Tricky手段。由于Celery需要阻塞线程执行,无法直接作为后台任务,我们还需要在应用开始时,将其使用另外一个线程开启。

Flask Auto Reloader

Flask_ 的开发者模式(准确的来说是 WerkZeug_ 作为基础类库提供的)提供了许多工具,比如基于页面的Debuger提供网页版的Shell。但是开发模式会默认将auto_reloader开启,好处是不用在修改逻辑后手工重启,坏处是他不是直接启动WebServer,而是从子线程中执行WebServer后,主线程执行一个本地文件Watcher,在文件发生变动时重启。

下图为调试模式下执行逻辑

CheckAndReloader过程中,一旦发现有.py[co]文件发生变更,则另外一个子进程,原进程退出。

为了复用逻辑,首次运行时不会直接执行 WebServer 部分,而是设置好环境变量WERKZEUG_RUN_MAIN后,进入sMain流程。下面为WerkZeugserving.py部分代码:

def run_with_reloader(main_func, extra_files=None, interval=1):    """Run the given function in an independent python interpreter."""    import signal    signal.signal(signal.SIGTERM, lambda *args: sys.exit(0))    if os.environ.get('WERKZEUG_RUN_MAIN') == 'true':        thread.start_new_thread(main_func, ())        try:            reloader_loop(extra_files, interval)        except KeyboardInterrupt:            return    try:        sys.exit(restart_with_reloader())    except KeyboardInterrupt:        pass

问题

麻烦在于,每一个在 Module 构建时创建对象,都会因为子进程的原因创建两次。

解决

不过既然知道了问题,我们屏蔽掉第一次执行母进程时的相关创建逻辑就行。接下来问题就转换为如何判断当前进程是否为子进程的问题。 方法有很多,比如根据系统环境变量来WERKZEUG_RUN_MAIN来判断。或者比较父进程组ID,因为子进程所属于父进程组,所以可以根据如下方法判断。

# avoid Werbzeg's `run(use_reloader=True)` will create subprocessif os.getppid() != os.getpgrp():    __start_celelry_worker()

Conclusion

虽然解决了 Module 作用域下变量创建在WerkZeug调试模式中创建两次的问题,但是就问题本身来说解决的很不优美。Flask插件通常会绑定到Flask.app创建之后,通过一个工厂方法调用。项目中的例子不是标准的 Flask 插件,所以会发生这类问题。如果调试模式增加一个 Hook 用于*正常逻辑*的执行也能解决这个问题。究其原因毕竟时基于 Flask 应用模块生命周期问题,Flask 已经提供了一套严禁的API,按照它提供的思路执行就是。所谓逆我者亡,也只能怪自己只猜中这开头,猜不中这结局。

很多同学的Sqlalchemy和Flask结合的问题也通常卡在维护 Session 生命周期上。选择一款框架绝对不是拿来主义,更多的是对原框架理念的一种赞同。

最后我还是考虑Mock掉这些API吧,哈哈。

Referencessubprocess – Work with additional processesget a lot knowledge of subprocess

singleton.py

The same question at StackOverflow

# 来源:HX


在微博上关注: 新浪, 腾讯 投稿

最新招聘

[北京] Python web开发程序员 – 译言 [北京] Python & Web前端研发工程师 – 北京邦富信息咨询有限公司 [广州] Python 开发工程师(Django) – 广州智品网络科技有限公司 [北京] Web前端开发程序员 – 译言 [上海] python工程师 – 上海客聚信息科技有限公司

更多>>

伟人所达到并保持着的高处,并不是一飞就到的,

Flask 如何实现 auto reloader

相关文章:

你感兴趣的文章:

标签云: