ydf0509 / funboost

pip install funboost,python全功能分布式函数调度框架,funboost的功能是全面性重量级,用户能想得到的功能99%全都有;funboost的使用方式是轻量级,只有@boost一行代码需要写。支持python所有类型的并发模式和一切知名消息队列中间件,支持如 celery dramatiq等框架整体作为funboost中间件,python函数加速器,框架包罗万象,用户能想到的控制功能全都有。一统编程思维,兼容50% python业务场景,适用范围广。只需要一行代码即可分布式执行python一切函数,99%用过funboost的pythoner 感受是 简易 方便 强劲 强大,相见恨晚 。
Apache License 2.0
682 stars 135 forks source link

定时任务如何实现分布式, 方式任务重复执行 #90

Closed dalibiao closed 10 months ago

dalibiao commented 11 months ago

如果启动多个定时任务进程, 同一个任务会重复执行.

ydf0509 commented 11 months ago

看下你启动代码,是怎么搞得

ydf0509 commented 11 months ago

1.你要发你的启动代码我看看才知道,你用什么job_store类型的apscheduler 2.如果你想粗暴的多次启动定时器,add_push_job中传入run_onceuuid入参就好了.

dalibiao commented 11 months ago

直接启动的这个脚本

from funboost.timing_job.apscheduler_use_redis_store import funboost_background_scheduler_redis_store from jobs.job1 import func_a

funboost_background_scheduler_redis_store.start(paused=False) funboost_background_scheduler_redis_store.add_push_job(func_a, trigger='interval', id='99', name='func_a', seconds=10, replace_existing=True)

dalibiao commented 11 months ago

可以启动呀 image image 这个定时器会每10秒往消息队列里面添加任务, 我启动了两个定时器任务进程, 所以每10秒会添加2个任务. 你是不是看错了, funboost_background_scheduler_redis_store.start(paused=False)这个方法里面paused=False, 会启动, 等于True才不会启动.

ydf0509 commented 11 months ago

也就是你把这个脚本启动了test2.py两次,那肯定是不行的. 因为你把定时任务启动了2次这样.

ydf0509 commented 11 months ago

那这样肯定是重复运行啊,你欧巴定时任务器启动了2次,每个定时任务器都是从redis获取要执行的任务的,你这样肯定不行的

ydf0509 commented 11 months ago

那你要学习apscheduler基本知识了啊,这个和funboost没关系.还是apschduler知识不扎实,但又不按照规定启动

dalibiao commented 11 months ago

所以我想问的是可不可以实现分布式定时任务, 因为我打算多态机器部署定时任务, apscheduler我之前接触过, 好像也不支持. 只能自定义分布式锁了. 我要问一下大牛有什么好的实现方案.

ydf0509 commented 11 months ago

如果你想动态修改定时任务,应该是在修改脚本里面 puased=True, 在启动定时任务的脚本里面 paused=False,这个文档有讲解.

属于apscheduler的基本知识了

ydf0509 commented 11 months ago

当然可以分布式的啊,你add_push_job 传入 runonce_uuid,那就随便你去无数次 apscheduler.start(paused=False) 了.

ydf0509 commented 11 months ago

你不需要分布式的多次运行apscheduler.start(paused=False) 启动定时任务啊,哎,你只需要apscheduler.start(paused=False) 一次就行了,别的地方改成paused=True. 你还是没理解定时任务在funboost中的角色.

apscheduler是负责定时任务发布消息到一个消息队列中,发布一条消息只要1毫秒,快得很, apscherulder吧消息发到消息队列后,由funboost执行函数消息本身,funboost来执行耗时任务,apscheduler只是执行个推送消息而已,所以你担心apscheduler的性能差需要分布式,那是完全是想多了.

ydf0509 commented 11 months ago

apscheduler在funboost中不会存在性能问题啊,他又不负责执行函数本身,为什么你非要把apscheduler来 apscheduler.start(paused=False) 在多台机器上运行呢, funboost才是执行函数需要消耗性能.

ydf0509 commented 11 months ago

感觉你没有理解apscheduler在funboost中的作用,以为apscheduler需要执行重型函数,apscheduler只是发布一条消息到消息队列.任务非常轻

ydf0509 commented 11 months ago

funboost+apscheduler这个和celery的定时任务一样的概念,定时任务只是负责定时把函数入参发到消息队列而已,并不负责直接执行函数啊.

dalibiao commented 11 months ago

考虑的场景不一样, 公司部署需要考虑容灾性, 如果定时器启动程序只在一台服务器上面. 如果这台服务器出现宕机, 定时器不就挂了. 现在的问题其实和funboost关系不大, 你说的原理我都知道, 我以前使用apscheduler和celery搭建的单机定时任务系统嵌入在flask里面

ydf0509 commented 11 months ago

定时任务吧消息定时发布到消息队列中,funboost多台机器分布式部署从一个消息队列拉取消息,funboost才是执行函数和入参

ydf0509 commented 11 months ago

考虑的场景不一样, 公司部署需要考虑容灾性, 如果定时器启动程序只在一台服务器上面. 如果这台服务器出现宕机, 定时器不就挂了. 现在的问题其实和funboost关系不大, 你说的原理我都知道, 我以前使用apscheduler和celery搭建的单机定时任务系统嵌入在flask里面

你这个也好办,你自己传入runonce_uuid可以阻止重复发布, 或者你在你的函数内部自己加redis过滤,不执行相同任务.

ydf0509 commented 11 months ago

image image

你看看这个

dalibiao commented 11 months ago

我知道你是把apscheduler当做定时器推送任务, 和celery-beat类似, 如果funboost集成到flask项目中, funboost_background_scheduler_redis_store定时器需要单独启动, 还是随着flask app一起启动呢.

另外加上runonce_uuid参数定时器就只会推一次任务进去了, 之后就不会push任务进去..... 定时器是不是应该在push任务之后删除runonce_uuid参数, 目的是同一个任务不会在同一时刻推送多次到任务队列里面 image

ydf0509 commented 11 months ago

1/ 如果你要从前端页面中请求flask来动态增删改定时任务,flask脚本里面肯定要启动定时任务的,但是务必设置apscheduler.start(paused=True), 如果你不执行start,你是无法增删改定时任务的. 2/ funboost_background_scheduler_redis_store还需要单独启动一次 .start(paused=false)

3/关于过滤重复任务,你可以不阻止重复推送,只阻止重复消费就行了.funboost 自带了入参过滤功能,并且可以设置多久时间之内过滤失效. 这些redis分布式过滤逻辑你也可以写在你的函数里面也行

ydf0509 commented 11 months ago

image

dalibiao commented 11 months ago

还有一个问题, boost的入参queue_name在装饰每一个函数都要是唯一的吗? 如何每一个函数都要设置一个queue_name, 如果有100个函数, 那在启动所有任务的时候是不是要python funboost_cli_user.py --booster_dirs_str=jobs consume q1 q2 q3....q100, 写100个queue_name, 有没有快捷的部署指令

ydf0509 commented 11 months ago

funboost不需要命令行部署,可以直接运行的,命令行不是必需品.

你自己for循环,把每个booster.consume也可以啊.

ydf0509 commented 11 months ago

queue_name最好是每个函数唯一的,不然的不同函数消息入参不一样,运行出错.

ydf0509 commented 11 months ago

文档第12章的在命令行敲击一大串字符串启动消费是个鸡肋,不如启动一个python文件

dalibiao commented 11 months ago

建议搞一个一键启动所用任务的方法, 类似于celery启动命令一样. 会自动寻找所有task

ydf0509 commented 11 months ago

早就有了. image

ydf0509 commented 11 months ago

你的消费函数很多吗,一般也就几十个吧最多

dalibiao commented 11 months ago

消费函数很多, 几百个... 可能是我设计的不太合理, 每一个异步方法都搞成了一个消费函数. 另外如果我开启了do_task_filtering执行任务会报一下错误, 是不是哪里设置不对... image image

ydf0509 commented 11 months ago

日志应该记录有错误堆栈的,不止错误描述

ydf0509 commented 11 months ago

这个地方,稍等,有效期的过滤,有个bug.之前按redis2版本开发的,redis3版本改了,我要改下.

ydf0509 commented 11 months ago

安装30.4版本 pip install funboost -i https://pypi.org/simple

ydf0509 commented 11 months ago

不过不建议用有效期过滤来房子重复运行,过滤是函数运行成功后才添加到redis的zset里面,你函数如果耗时2秒,那还是重复运行的,你可以在你的消费函数里面加sleep测试就能验证了.

你自己在函数里面加redis逻辑吧,这个不难

ydf0509 commented 11 months ago

cahtgtp已经告诉你5种方式房子定时任务重复运行了.

dalibiao commented 11 months ago

不过不建议用有效期过滤来房子重复运行,过滤是函数运行成功后才添加到redis的zset里面,你函数如果耗时2秒,那还是重复运行的,你可以在你的消费函数里面加sleep测试就能验证了.

你自己在函数里面加redis逻辑吧,这个不难 我重写了一下push_fun_params_to_broker, 这样就可以保证任务只会执行一次了. image

ydf0509 commented 11 months ago

你这样加肯定不行啊,托女裤子放屁那不是.那另外一个脚本不是又能发布了

ydf0509 commented 11 months ago

你sadd马上又删除了,那还不是可以重复发布.

ydf0509 commented 11 months ago

我说的是你自己在你的消费函数里面增加redis的逻辑啊,不需要改动funboost源码.

dalibiao commented 11 months ago

我说的是你自己在你的消费函数里面增加redis的逻辑啊,不需要改动funboost源码.

我没有改源码呀, 我是重写的一个方法, 测试过是可以解决同一时刻一个任务只运行一次. 现在这种实现简单粗暴, 我再优化一下