1问题描述:

flask自带的reload只能在语法没毛病的情况下auto_relaod,但是如果有语法错误,进程就会报错退出。

这时修改完语法错误,还得在控制台按“↑”和“enter”重新执行一次python3 app.py 重新启动flask。

希望省掉手动重启flask的过程

2解决方案

用flask-failsafe插件。

这样语法错误也会reload,语法错误修正,系统继续运行。这样手和光标不用频繁切到控制台,也省了“↑”和“enter”的按键。懒人专用。

这个插件使用很简单:

myapp模拟flask应用。main.py作为启动脚本。核心就是装饰器,监控各种文件改动。然后reraise。

3原理

(好奇心不强的可以不看)

虽然flask_failsafe是代码只有80行的一个单独py文件,但是还不是太能看懂啊啊……把我理解的作为注释加进去了:

import functools
import sys
import traceback import flask PY2 = sys.version_info[0] == 2 def failsafe(func):
"""
Wraps an app factory to provide a fallback in case of import errors. Takes a factory function to generate a Flask app. If there is an error
creating the app, it will return a dummy app that just returns the Flask
error page for the exception. This works with the Flask code reloader so that if the app fails during
initialization it will still monitor those files for changes and reload
the app.
""" @functools.wraps(func)
def wrapper(*args, **kwargs):
extra_files = [] try:
    #如果create_app运行不报错。就直接在开头退出。
return func(*args, **kwargs)
except:
#捕获异常,并打印
exc_type, exc_val, exc_tb = sys.exc_info()
traceback.print_exc()
#添加异常中依赖的文件,和“SyntaxError”爆出来的文件。
tb = exc_tb
while tb:
filename = tb.tb_frame.f_code.co_filename
extra_files.append(filename)
tb = tb.tb_next if isinstance(exc_val, SyntaxError):
extra_files.append(exc_val.filename)
#启动dummy app,专门用来显示错误的文件
app = _FailSafeFlask(extra_files)
app.debug = True @app.route('/')
@app.route('/<path:path>')
def index(path='/'):
reraise(exc_type, exc_val, exc_tb) return app return wrapper if PY2:
exec('def reraise(tp, value, tb=None):\n raise tp, value, tb')
else:
def reraise(tp, value, tb=None):
if value.__traceback__ is not tb:
raise value.with_traceback(tb)
raise value class _FailSafeFlask(flask.Flask):
"""
Binds the extra_args parameter of run() to include the extra files we want to
monitor for changes.
""" def __init__(self, extra_files):
flask.Flask.__init__(self, __name__)
self.extra_files = extra_files def run(self, *args, **kwargs):
extra_files = self.extra_files
if 'extra_files' in kwargs:
extra_files = extra_files + kwargs['extra_files']
kwargs['extra_files'] = extra_files
flask.Flask.run(self, *args, **kwargs)

关键好像是最后2行 flask自己会跟踪'extra_files'文件的改动。又百度了一下,准确地说是werkzeug用子进程实现的这个功能。后面会简单说到原理。

当extra_files有改动后,dummy_app跟踪改动,flask的auto_loader机制会保证dummy_app先退出,再重启

关键就是这个重启,为什么能重复执行我们写的create_app,而不是简单重启dummy_app.run()呢?

根据flask的auto_reloader机制的讲解,

当从进程执行到run_with_reloader时,便进入了条件分支,而不会再无限启新的「从进程」耗光资源。而分支内部可以看到,开了一条线程来跑main_func也就是启动web服务的方法,紧接着启动reloader_loop也就是监视文件改动的循环。

大概是:werkzeug的自动重启机制是:用我们传进去的命令行参数,通过subprocess建立新的python解释器。也就是在新进程执行"python3 main.py"

这也就保证了main.py里我们的create_app()会在文件被修改后执行,这个和flask-failsafe没有关系。

对比一下重启过程:

普通的flask app是这样的:

1文件被改动,werkzeug的子进程会监控到改动,然后报exitcode 3退出

2 werkzeug试图重启subprocess(用我们开始传入的参数python main.py 执行create_app() 和app.run())

3 如果重启中出现语法错误,就会报错非exitcode 3,先退出子进程,再退出主进程;

而文艺的flask-failsafe 1 2是一样的,但之后就不一样了,它要实现“如果create_app失败,不会退出主进程,继续监控出错的文件,出错文件被改动后试图重新运行create_app”:

3 如果重启时在create_app里出现语法错误,捕获异常,根据异常报出来的文件构造extra_files

4 用extra_files参数启动一个dummy_app代替用户本来想创建的app

5 dummy_app.run()正常运行,但其实dummy_app什么都不做,因为这时有文件是错的。

6如果有文件改动了,重复1

这个dummy_app巧妙性在于,充分利用了werkzeug的强大的自动重启机制:

  1它会正常启动,正常run。因为它本身并没有import或用到这些出错的extra_files,只是个超级简单的app

2它保留了我们传入的arg和kwarg用于启动subprocess。在这一点上,它的行为和原生的app一样,所以它一旦退出,subprocess重启,会导致重启我们写的create_app,试图创建我们的app, 而不是简单重建自己。

3它会跟踪错误的extra_files的改动而触发werkzeug的重启机制。

所以,如果没有werkzeug基于subprocess,重启新解释器的重启机制,是没法实现重新执行create_app的。

以我的水平,理解到这样就基本满意啦。

让flask在出现语法错误时仍然自动重启的更多相关文章

  1. Note Pad++ 关闭语法错误时在代码下面的红线标识

    菜单栏 —- 插件 —- DSpellCheck . 将勾去掉即可

  2. 用Supervisor实现进程守护,在异常退出时自动重启

    程序启动后,有些是以daemon的形式运行,但在意外退出后,如果不能及时重新启动,会有比较严重的影响. 比如Zimg在图片处理中由于某些图片处理失败,会导致zimg进程挂掉,影响正常的服务提供,并且只 ...

  3. SQL SERVER 重组含有特殊字符的索引时遇到“关键字 'with' 附近有语法错误.”

    案例描述 这是在索引重组过程中遇到的有意思的错误案例,搜索了一下也没有看到相关资料,估计我第一个碰到这类错误的人(It's just a joke).具体情况是YourSQLDba在做维护数据库索引时 ...

  4. LoadRunner 11安装Micosoft Visual C++ 2005 SP1时提示命令行选项语法错误

    如果安装LoadRunner 11时弹窗提示"Micosoft Visual C++ 2005 SP1 可再发行组件包(X86):'命令行选项语法错误.键入命令 / ? 可获得帮助信息'&q ...

  5. 解决SQL将varchar值转换为数据类型为int的列时发生语法错误

    今天遇到一个这样的错误,具体的报错情况如下 解决的方案如下. 数据库MSSQL在比较大小时,出错提示:“将 varchar 值 '24.5' 转换为数据类型为 int 的列时发生语法错!”分析数据库设 ...

  6. 安装loadrunner时出现”命令行选项语法错误键入命令 \?获得帮助“的解决方法

    安装LR11 时,安装Microsoft Visual c++2005 sp1运行时组件,就会提示命令行选项语法错误,键入“命令/?”可获取帮肋信息1.进入loadrunner-11\Addition ...

  7. notepad++新建文档时,会出现语法错误的红色下波浪线

    notepad++新建文档时,会出现语法错误的红色下波浪线: 原因:新建文档时默认设置语言为PHP. 解决方法:修改默认语言为java或JavaScript,如下: 小结:打开文档时,也可能出现下波浪 ...

  8. Mybatis 的 xml 文件语法错误,启动项目时控制台一直循环解析但是不打印错误

    重写SqlSessionFactoryBean的buildSqlSessionFactory方法: eg: package com.slp; import java.io.IOException; i ...

  9. 关于SubSonic3.0未处理InvalidOperationException异常(关键字TOP附近有语法错误)的处理

    早上在测试程序时,使用了Top这个属性,没想到马上抛出了个“未处理InvalidOperationException异常(关键字'TOP'附近有语法错误)”这个错误提示,见下图: 然后Debug一下, ...

随机推荐

  1. Sizzle源码分析 (一)

    Sizzle 源码分析 (一) 2.1 稳定 版本 Sizzle 选择器引擎博大精深,下面开始阅读它的源代码,并从中做出标记 .先从入口开始,之后慢慢切入 . 入口函数 Sizzle () 源码 19 ...

  2. Python zip() 处理多于两个序列的参数, 存储结对的值

    zip() 可以接受多于两个的序列的参数.这时候所生成的结果元组中元素个数跟输入序列个数一样 >>> a = [1, 2, 3] >>> b = [10, 11, ...

  3. Linux基础命令---cmp

    cmp 用字节的方式,比较两个文件是否存在差异,但是不保存运算结果.Cmp指令只会根据结果设置相关的标志位,这个指令之后往往会跟着一个条件跳转指令. 此命令的适用范围:RedHat.RHEL.Ubun ...

  4. corejDay1

    1.内部类: 有什么用? 1.可以访问该类定义所在作用域中的数据,包括私有数据. 2.当想定义一个回调函数而不想编写大量代码时,使用匿名内部类比较便捷. 3.内部类可以对同一个包中的其他类隐藏起来. ...

  5. UVA12558 Egyptian Fractions (HARD version) (埃及分数,迭代加深搜索)

    UVA12558 Egyptian Fractions (HARD version) 题解 迭代加深搜索,适用于无上界的搜索.每次在一个限定范围中搜索,如果无解再进一步扩大查找范围. 本题中没有分数个 ...

  6. 20145311王亦徐《网络对抗技术》MAL_逆向与Bof基础

    20145311王亦徐<网络对抗技术>MAL_逆向与Bof基础 实践目标 运行一个可执行文件,通过逆向或者Bof技术执行原本不应该执行的代码片段采用的两种方法: 1.利用foo函数的Bof ...

  7. Windows Services 学习(转载)

    转载:http://blog.csdn.net/fakine/article/details/42107571 一.学习点滴 1.本机服务查看:services.msc /s2.服务手动安装(使用sc ...

  8. C++11标准 STL正则表达式 验证电子邮件地址

    转自:http://www.cnblogs.com/yejianfei/archive/2012/10/07/2713715.html 我们最经常遇到的验证,就是电子邮件地址验证.网站上常见.各种网页 ...

  9. java.lang.NoClassDefFoundError错误

    根据前文,很明显NoClassDefFoundError的错误是因为在运行时类加载器在classpath下找不到需要加载的类,所以我们需要把对应的类加载到classpath中,或者检查为什么类在cla ...

  10. Ruby基础教程

    一.Ruby基础知识 1.关于Ruby Ruby是脚本语言 Ruby是面向对象语言 Ruby是跨平台语言 Ruby是开放源码软件 2.Ruby入门书籍推荐 <Ruby.Programming向R ...