在应用中需要使用调度框架来做一些统计的功能,可惜在Windows上可用的不多,最后选择了APScheduler这个调度器。
用法不多介绍,只总结一下在使用中遇到的坑。
app_context 问题
凡是在APScheduler中调用的function,只要用到初始化跟app相关的对象(如db,mail),都是需要app上下文的,正常情况下都需要push app_context的。
否则将会报"No application found. Either work inside a view function or push an application context."的错误。
因为Flask-APScheduler在运行的时候是单独的一个进程,在这个进程中app是没有实例化的。使用之前要先实例化app对象。
以下代码可以解决这个问题:
#此创建app实例 def get_app(): flask_app=create_app('production') return flask_app def job1(): with get_app().app_context(): #需要做的操作
重复运行问题
在create_app时同时创建APScheduler对象,并且init然后start,会出现一个重复运行的问题。
那是因为FastCGI进程管理器在Web Server启动时,会自动创建若干个进程等待客户端的连接。如果访问量比较大,FastCGI会创建更多的进程以响应客户端的连接。
而每启动一个进程都会在后台创建一个APScheduler对象,所以会出现重复运行的情况。
在Linux上可以通过Python的fcntl包获得一个文件的排他锁,以达到只启动一个APScheduler对象的功能。但是在Windows上没有相应的包。
试过很多种获得文件排他锁的方法,终于找到一个第三方的包:portalocker,果断安装。
使用方法如下:
scheduler=APScheduler() def create_app(config_name): app=Flask(__name__) app.jinja_env.trim_blocks=True app.config.from_object(config[config_name]) config[config_name].init_app(app) scheduler_init(app) return app def scheduler_init(app): try: lockfile=open('scheduler.lock','w') portalocker.lock(lockfile,portalocker.LOCK_EX | portalocker.LOCK_NB) lockfile.write(str(datetime.datetime.now())) scheduler.init_app(app) scheduler.start() except: pass def _unlock_file(): try: portalocker.unlock(lockfile) except: pass atexit.register(_unlock_file)
获得锁的进程,在解释器被销毁时会调用_unlock_file释放锁,新创建的进程又会得到锁,所以APScheduler会一直运行。 如果要想获得准确调度,可以使用APScheduler另外启动一个进程,而不要使用Flask-APScheduler。 不过Flask-APScheduler对我的应用来说够用了。