让flask在出现语法错误时仍然自动重启
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在出现语法错误时仍然自动重启的更多相关文章
- Note Pad++ 关闭语法错误时在代码下面的红线标识
菜单栏 —- 插件 —- DSpellCheck . 将勾去掉即可
- 用Supervisor实现进程守护,在异常退出时自动重启
程序启动后,有些是以daemon的形式运行,但在意外退出后,如果不能及时重新启动,会有比较严重的影响. 比如Zimg在图片处理中由于某些图片处理失败,会导致zimg进程挂掉,影响正常的服务提供,并且只 ...
- SQL SERVER 重组含有特殊字符的索引时遇到“关键字 'with' 附近有语法错误.”
案例描述 这是在索引重组过程中遇到的有意思的错误案例,搜索了一下也没有看到相关资料,估计我第一个碰到这类错误的人(It's just a joke).具体情况是YourSQLDba在做维护数据库索引时 ...
- LoadRunner 11安装Micosoft Visual C++ 2005 SP1时提示命令行选项语法错误
如果安装LoadRunner 11时弹窗提示"Micosoft Visual C++ 2005 SP1 可再发行组件包(X86):'命令行选项语法错误.键入命令 / ? 可获得帮助信息'&q ...
- 解决SQL将varchar值转换为数据类型为int的列时发生语法错误
今天遇到一个这样的错误,具体的报错情况如下 解决的方案如下. 数据库MSSQL在比较大小时,出错提示:“将 varchar 值 '24.5' 转换为数据类型为 int 的列时发生语法错!”分析数据库设 ...
- 安装loadrunner时出现”命令行选项语法错误键入命令 \?获得帮助“的解决方法
安装LR11 时,安装Microsoft Visual c++2005 sp1运行时组件,就会提示命令行选项语法错误,键入“命令/?”可获取帮肋信息1.进入loadrunner-11\Addition ...
- notepad++新建文档时,会出现语法错误的红色下波浪线
notepad++新建文档时,会出现语法错误的红色下波浪线: 原因:新建文档时默认设置语言为PHP. 解决方法:修改默认语言为java或JavaScript,如下: 小结:打开文档时,也可能出现下波浪 ...
- Mybatis 的 xml 文件语法错误,启动项目时控制台一直循环解析但是不打印错误
重写SqlSessionFactoryBean的buildSqlSessionFactory方法: eg: package com.slp; import java.io.IOException; i ...
- 关于SubSonic3.0未处理InvalidOperationException异常(关键字TOP附近有语法错误)的处理
早上在测试程序时,使用了Top这个属性,没想到马上抛出了个“未处理InvalidOperationException异常(关键字'TOP'附近有语法错误)”这个错误提示,见下图: 然后Debug一下, ...
随机推荐
- .NET MVC model数据验证
MVC提供了很方便的数据验证,只需要在model里加入相关的正则等,那么就会在前台里生成相关的验证脚本.需要引用两个js文件: jquery.validate.min.js jquery.valida ...
- Object-C-属性参数
assign:默认参数setter 方法不会引起引用计数的变化 retain:setter方法首先释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的引用计数为1 copy:setter 方法首先 ...
- linux服务器---squid缓存
Squid缓存 代理服务器会在本地硬盘设置缓存,这样可以提高网络效率 1修改squid配置文件“/etc/squid/squid.conf”,参数“cache_dir_ufs”就是设置缓存目录的 [r ...
- Python Web学习笔记之并发和并行的区别和实现
你吃饭吃到一半,电话来了,你一直到吃完了以后才去接,这就说明你不支持并发也不支持并行.你吃饭吃到一半,电话来了,你停了下来接了电话,接完后继续吃饭,这说明你支持并发.你吃饭吃到一半,电话来了,你一边打 ...
- Python入门之面向对象的__init__和__new__方法
Python入门之面向对象的__init__和__new__方法
- Antlr4 SQL Query 解析实例
grammar MysqlQuery; @header{package com.antlr.mysql.query;} AS : A S; SELECT : S E L E C T; FROM : F ...
- 一些应该使用mongodb或者其他文档存储而不是redis或mysql、oracle json的情形(最近更新场景)
通常来说,我们应该使用应用的特性而不是自己的爱好或者规定而去选择一种合适的组件,选择的标准应该是这个组件最适合或者本身其设计就是为了解决这个问题,而不是这个组件能够做这事情为标准.就拿存储来说,任何时 ...
- 04: Mysql性能优化
MySQL其他篇 目录: 参考网站 1.1 Mysql数据库的优化技术 1.2 数据库表设计 1.3 SQL优化 1.为查询缓存优化你的查询 2.EXPLAIN 你的 SELECT 查询 3. 当只要 ...
- ELK之elasticsearch6.5集群
前面介绍并初试了es6.5系列的单节点的操作,现在搭建es6.5系列的集群: 环境:三节点:master-172.16.23.128.node1-172.16.23.129.node2-172.16. ...
- intent bundle的使用
1.什么是bundle Bundle主要用于传递数据:它保存的数据,是以key-value(键值对)的形式存在的.我们经常使用Bundle在Activity之间传递数据,传递的数据可以是boolean ...