基于多进程中APScheduler重复运行的解决方法


Posted in Python onJuly 22, 2019

问题

在一个python web应用中需要定时执行一些任务,所以用了APScheduler这个库。又因为是用flask这个web框架,所以用了flask-apscheduler这个插件(本质上与直接用APScheduler一样,这里不作区分)。

在开发中直接测试运行是没有问题的,但是用gunicorn部署以后发生了重复运行的问题:

每个任务在时间到的时刻会同时执行好几遍。

注意了一下重复的数量,恰恰是gunicorn里配置的worker进程数量,显然是每个worker进程都启动了一份scheduler造成。

解决

可以想到的方案有几个:

用--preload启动gunicorn,确保scheduler只在loader的时候创建一次

另外创建一个单独的定时任务项目,单独以一个进程运行

用全局锁确保scheduler只运行一次

经过实践,只有第三个方案比较好。

preload的问题:

虽然这样可以使用scheduler创建代码只执行一次,但是问题也在于它只执行一次,重新部署以后如果用kill -HUP重启gunicorn,它并不会重启,甚至整个项目都不会更新。这是preload的副作用,除非重写部署脚本,完全重启应用。

单独进程的问题:

也是因为部署麻烦,需要多一套部署方案,虽然用Docker会比较方便,但仍然不喜欢,而且同时维护两个项目也多出很多不必要的事情。

全局锁是一个较好的方案,但问题在于找一个合适的锁。

python自带的多进程多线程锁方案都需要一个共享变量来维护,但是因为worker进程是被gunicorn的主进程启动的,并不方便自己维护,所以需要一个系统级的锁。

在Stackoverflow上看到有人是用了一个socket端口来做锁实现这个方案,但是我也不喜欢这样浪费一个宝贵的端口资源。不过这倒给了我一个启发:

可以用文件锁!

于是有了这个解决方案:

import atexit
import fcntl
from flask_apscheduler import APScheduler

def init(app):
 f = open("scheduler.lock", "wb")
 try:
  fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
  scheduler = APScheduler()
  scheduler.init_app(app)
  scheduler.start()
 except:
  pass
 def unlock():
  fcntl.flock(f, fcntl.LOCK_UN)
  f.close()
 atexit.register(unlock)

原理

init函数为flask项目初始化所调用,这里为scheduler模块的初始化部分。

首先打开(或创建)一个scheduler.lock文件,并加上非阻塞互斥锁。成功后创建scheduler并启动。

如果加文件锁失败,说明scheduler已经创建,就略过创建scheduler的部分。

最后注册一个退出事件,如果这个flask项目退出,则解锁并关闭scheduler.lock文件的锁。

以上这篇基于多进程中APScheduler重复运行的解决方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
在Linux上安装Python的Flask框架和创建第一个app实例的教程
Mar 30 Python
详解python开发环境搭建
Dec 16 Python
Python实现将数据库一键导出为Excel表格的实例
Dec 30 Python
python中利用xml.dom模块解析xml的方法教程
May 24 Python
python cx_Oracle的基础使用方法(连接和增删改查)
Nov 19 Python
Python 依赖库太多了该如何管理
Nov 08 Python
Python 生成一个从0到n个数字的列表4种方法小结
Nov 28 Python
Transpose 数组行列转置的限制方式
Feb 11 Python
Python itertools.product方法代码实例
Mar 27 Python
Python requests.post方法中data与json参数区别详解
Apr 30 Python
django queryset 去重 .distinct()说明
May 19 Python
Tensorflow与RNN、双向LSTM等的踩坑记录及解决
May 31 Python
django云端留言板实例详解
Jul 22 #Python
python实现图片中文字分割效果
Jul 22 #Python
django用户登录验证的完整示例代码
Jul 21 #Python
Python Threading 线程/互斥锁/死锁/GIL锁
Jul 21 #Python
详解Django模版中加载静态文件配置方法
Jul 21 #Python
django数据库自动重连的方法实例
Jul 21 #Python
django使用django-apscheduler 实现定时任务的例子
Jul 20 #Python
You might like
一棵php的类树(支持无限分类)
2006/10/09 PHP
简单的PHP留言本实例代码
2010/05/09 PHP
PHP使用range协议实现输出文件断点续传代码实例
2014/07/04 PHP
[原创]smarty简单模板变量输出方法
2016/07/09 PHP
JavaScript 闭包在封装函数时的简单分析
2009/11/28 Javascript
ExtJS下grid的一些属性说明
2009/12/13 Javascript
Javascript学习笔记7 原型链的原理
2010/01/11 Javascript
JS实现根据出生年月计算年龄
2014/01/10 Javascript
在jquery boxy中添加百度地图坐标拾取注意流程
2014/04/03 Javascript
Javascript基础知识(二)事件
2014/09/29 Javascript
详解jquery中$.ajax方法提交表单
2014/11/03 Javascript
jQuery焦点图左右转换效果
2016/12/12 Javascript
微信小程序 商城开发(ecshop )简单实例
2017/04/07 Javascript
js实现倒计时关键代码
2017/05/05 Javascript
angular6.0开发教程之如何安装angular6.0框架
2018/06/29 Javascript
使用typescript构建Vue应用的实现
2019/08/26 Javascript
webpack HappyPack实战详解
2019/10/08 Javascript
如何配置vue.config.js 处理static文件夹下的静态文件
2020/06/19 Javascript
Python+selenium实现截图图片并保存截取的图片
2018/01/05 Python
浅谈Pycharm调用同级目录下的py脚本bug
2018/12/03 Python
解决.ui文件生成的.py文件运行不出现界面的方法
2019/06/19 Python
python数字类型math库原理解析
2020/03/02 Python
把Anaconda中的环境导入到Pycharm里面的方法步骤
2020/10/30 Python
Python urllib3软件包的使用说明
2020/11/18 Python
Python实现淘宝秒杀功能的示例代码
2021/01/19 Python
纯CSS3打造动感漂亮时尚的扇形菜单
2014/03/18 HTML / CSS
CSS3 RGBA色彩模式使用实例讲解
2016/04/26 HTML / CSS
美国第一个网上卖鞋零售商:OnlineShoes.com
2017/09/24 全球购物
自我鉴定范文200字
2013/10/02 职场文书
七匹狼男装广告词
2014/03/21 职场文书
秋天的怀念教学反思
2014/04/28 职场文书
2016年企业安全生产月活动总结
2016/04/06 职场文书
详解MySQL连接挂死的原因
2021/05/18 MySQL
Java框架入门之简单介绍SpringBoot框架
2021/06/18 Java/Android
JVM之方法返回地址详解
2022/02/28 Java/Android
基于Python实现流星雨效果的绘制
2022/03/18 Python