让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一下, ...
随机推荐
- VMWARE安装centos6 http://www.centoscn.com/image-text/setup/2013/0816/1263.html
http://www.centoscn.com/image-text/setup/2013/0816/1263.html
- html lang属性
HTML 的 lang 属性可用于网页或部分网页的语言.这对搜索引擎和浏览器是有帮助的. 根据 W3C 推荐标准,您应该通过 <html> 标签中的 lang 属性对每张页面中的主要语言进 ...
- Python: 类中为什么要定义__init__()方法
学习并转自:https://blog.csdn.net/geerniya/article/details/77487941 1. 不用init()方法定义类 定义一个矩形的类,目的是求周长和面积. c ...
- Python tricks(7) -- new-style class的__slots__属性
__slots__是在python 2.2开始引入的一个新特性, 我们来看一下官方给出的解释. This class variable can be assigned a string, iterab ...
- Linux服务器配置---ftp用户黑名单
用户黑白名单 一个Linux主机中会多个用户,而我们希望有些用户不能去访问ftp.ftp服务器可以通过配置文件“/etc/vsftpd/user_list”来设置一个用户列表,这个列表可以是黑名单,也 ...
- 解析分布式锁之Redis实现(二)
摘要:在前文中提及了实现分布式锁目前有三种流行方案,分别为基于数据库.Redis.Zookeeper的方案,本文主要阐述基于Redis的分布式锁,分布式架构设计如今在企业中被大量的应用,而在不同的分布 ...
- go环境搭建—基于CentOS6.8
1. 背景 在当前的中国网络环境下,我们无法访问Google的服务的,包括Golang.org.从第三方网站下载预编译的二进制Go发行版可能存在第三方源代码注入的风险,例如之前的XcodeGhost. ...
- 【LTE基础知识】SGLTE, SVLTE, CSFB, VoLTE【转】
本文转载自:https://blog.csdn.net/henryghx/article/details/18416405 4G网络下实现语音通话功能的技术共有三种——VoLTE.SGLTE(GSM ...
- HDU 6148 Valley Numer (数位DP)题解
思路: 只要把status那里写清楚就没什么难度T^T,当然还要考虑前导零! 代码: #include<cstdio> #include<cstring> #include&l ...
- BZOJ1632: [Usaco2007 Feb]Lilypad Pond SPFA+最短路计数
Description 为了让奶牛们娱乐和锻炼,农夫约翰建造了一个美丽的池塘.这个长方形的池子被分成了M行N列个方格(1≤M,N≤30).一些格子是坚固得令人惊讶的莲花,还有一些格子是岩石,其余的只是 ...