基于多进程中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 相关文章推荐
python在windows命令行下输出彩色文字的方法
Mar 19 Python
python 回调函数和回调方法的实现分析
Mar 23 Python
python 采集中文乱码问题的完美解决方法
Sep 27 Python
基于Python os模块常用命令介绍
Nov 03 Python
python使用Apriori算法进行关联性解析
Dec 21 Python
使用Python搭建虚拟环境的配置方法
Feb 28 Python
python web基础之加载静态文件实例
Mar 20 Python
Python2和Python3.6环境解决共存问题
Nov 09 Python
Python设计模式之策略模式实例详解
Jan 21 Python
正则给header的冒号两边参数添加单引号(Python请求用)
Aug 09 Python
Python常用数字处理基本操作汇总
Sep 10 Python
python scrapy简单模拟登录的代码分析
Jul 21 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
PHP5下$_SERVER变量不再受magic_quotes_gpc保护的弥补方法
2012/10/31 PHP
使用PHP生成二维码的方法汇总
2015/07/22 PHP
谈谈PHP连接Access数据库的注意事项
2016/08/12 PHP
redis查看连接数及php模拟并发创建redis连接的方法
2016/12/15 PHP
PHP高并发和大流量解决方案整理
2021/03/09 PHP
jQuery模拟点击A标记示例参考
2014/04/17 Javascript
JavaScript验证图片类型(扩展名)的函数分享
2014/05/05 Javascript
整理Javascript函数学习笔记
2015/12/01 Javascript
AngularJs 弹出模态框(model)
2016/04/07 Javascript
JavaScript中获取时间的函数集
2016/08/16 Javascript
ubuntu编译nodejs所需的软件并安装
2017/09/12 NodeJs
通过jQuery学习js类型判断的技巧
2019/05/27 jQuery
node 解析图片二维码的内容代码实例
2019/09/11 Javascript
JavaScript监听键盘事件代码实现
2020/06/03 Javascript
在vue中使用Echarts利用watch做动态数据渲染操作
2020/07/20 Javascript
vue3+typescript实现图片懒加载插件
2020/10/26 Javascript
[05:28]刀塔密之一:团结则存
2014/07/03 DOTA
非递归的输出1-N的全排列实例(推荐)
2017/04/11 Python
python 将数据保存为excel的xls格式(实例讲解)
2018/05/03 Python
对python中使用requests模块参数编码的不同处理方法
2018/05/18 Python
创建pycharm的自定义python模板方法
2018/05/23 Python
python中的反斜杠问题深入讲解
2019/08/12 Python
详解有关PyCharm安装库失败的问题的解决方法
2020/02/02 Python
tensorflow2.0保存和恢复模型3种方法
2020/02/03 Python
python之MSE、MAE、RMSE的使用
2020/02/24 Python
详解HTML5 canvas绘图基本使用方法
2018/01/29 HTML / CSS
医学院校毕业生自荐信范文
2014/01/01 职场文书
科级干部考察材料
2014/02/15 职场文书
2014年四风问题个人对照自查剖析材料
2014/09/15 职场文书
浪漫婚礼主题活动策划方案
2014/09/15 职场文书
2014办公室副主任四风对照检查材料思想汇报
2014/09/20 职场文书
学生退学证明
2015/06/23 职场文书
2015年中秋寄语
2015/07/31 职场文书
详解OpenCV曝光融合
2022/04/29 Python
Mysql InnoDB 的内存逻辑架构
2022/05/06 MySQL
Android学习之BottomSheetDialog组件的使用
2022/06/21 Java/Android