测试平台系列(82) 解决APScheduler重复执行的问题
大家好~我是
米洛!
我正在从0到1打造一个开源的接口测试平台, 也在编写一套与之对应的完整教程,希望大家多多支持。
欢迎关注我的公众号测试开发坑货,获取最新文章教程!
回顾
上一节我们编写了在线执行Redis命令的功能,页面也勉强能用了。对于前置条件这块来说,就好像沙鲁吞了17号,已经算半个
完全体了。
我们趁热打铁,解决一下因为部署多机器引发的Apscheduler重复执行的问题。
APScheduler带来的问题
APScheduler其实本质上还是一个
定时任务组件,它并没有celery那么强大复杂的系统。针对多台机器,或者uvicorn(gunicorn)的多个worker,它是会
重复执行的。
这里感谢一下小右君,他告诉我前面有大坑。
像我们平时那么启动:
if __name__ == "__main__": uvicorn.run(app='main:pity', host='0.0.0.0', port=7777)
这样
其实只开了1个worker,你想呀,1个工人执行定时任务,当然不存在竞争的问题,但多个工人一起执行,你就存在
信息不对称的问题。
工人A到点了,要干活了,他不知道B也准备干同样的活儿,所以任务重复执行的问题,就出现了。
解决问题的方向
我只启动1个worker
有点傻,而且性能不好使,多台机器部署依然有问题。
推荐指数: 0颗星
- 初始化sceduler的时候,利用socket占据一个固定的端口比如2333
端口号只能被1个worker占领,其他worker拿不到,也就起不来了。但还是不能支持多节点部署,实际上只有1个worker使用,浪费了1个
端口。
推荐指数: ⭐⭐⭐
- 分布式锁
不够轻量,需要引入第三方组件如: Redis/Zookeeper/
Etcd。但能很好解决多worker和多节点的问题。
推荐指数: ⭐⭐⭐
办法很多,但是好用的
真不多。由于我们本身就需要引入Redis,还是秉着不滥用中间件的原则,所以我们打算用Redis的分布式锁。
而关于redis分布式锁,有很多介绍。我们用牛人们封装好的RedLock来帮我们解决同时执行问题。
Redlock
比起自己setnx+用lua脚本保障分布式锁执行,官方后面给出了redlock的解决方案。更多这些细节可以自行搜索
Redlock。
我们这边采用第三方的库: Redlock来简化我们的开发。
基本上用with获取lock,传入redis节点信息即可,接着我们就可以编写相关代码了。
我们还是用装饰器的方法,在想要加锁的方法引入此装饰器。key是自己定义的执行key,用于确定锁的唯一性。
分布式锁的原理就是多台设备同时去试图创建key,先创建成功的就执行对应的操作。所以对于所有节点来说,key必须都统一起来,并且不能和其他分布式锁的key冲突。
import functools import os from redlock import RedLock, RedLockError from config import Config def lock(key): def decorator(func): @functools.wraps(func) async def wrapper(*args, **kwargs): try: # 试图获取分布式锁,如果没有获取到则会抛出RedLockError,所以我们这里捕获它 with RedLock(f"distributed_lock:{func.__name__}:{key}:{str(args)}", connection_details=Config.RedisCluster, ): return await func(*args, **kwargs) except RedLockError: print(f"进程: {os.getpid()}获取任务失败, 不用担心,还有其他哥们给你执行了") return wrapper return decorator
关于唯一key的确认,我这边首先加上了
distributed_lock的前缀,是因为方便区分其他key,接着通过函数名称+唯一key确认分布式key,但由于有的方法是带
参数的,所以我选择再加一个args,来支持那些同方法不同参数的任务。
运用到pity之中
我们只需要在run_test_plan方法加上lock这个装饰器即可,总体来说还是
非常方便的。
如果需要测试的话,大家可以用以下命令启动pity:
uvicorn main:pity --host=0.0.0.0 --port=7777 --workers=4
可以看到,日志都输出了4份,因为有4个worker。用这个模式启动
PITY的话,可以看到对应的效果。
关于Redlock,这节就介绍到这里了。下一节我们要在前置条件中支持Redis语句,敬请期待吧。
- CGYWIN 编译的可执行程序在WINDOWS平台中运行时,解决system函数不能使用的问题
- Spring的Quartz定时器同一时刻重复执行二次的问题解决
- Spring的Quartz定时器同一时刻重复执行二次的问题解决
- 解决Spring定时计划任务重复执行两次(实例被构造两次)问题的方法
- 解决hibernate双向关系造成的一方重复执行SQl,或者死循环的问题
- 解决Spring定时计划任务重复执行两次(实例被构造两次)问题的方法
- 使用redis分布式锁解决spring schedule集群部署重复执行问题
- ubuntu下ibus输入平台安装sunpinyin步骤及出现的系列问题解决方案
- Spring的quartz定时器同一时刻重复执行二次的问题解决
- 使用maven-shade-plugin构建可执行jar 解决junit4测试问题 maven项目
- 解决多进程中APScheduler重复运行的问题
- 解决 集群 环境 定时任务 重复执行 的问题
- Linux下shell脚本在crontab中一个周期执行不完,下周期任务被重复执行的问题解决
- Node解决简单重复问题系列之Excel内容的获取
- 解决夜间需要不停重启机器的自动化测试脚本执行问题
- Spring的quartz定时器同一时刻重复执行二次的问题解决
- Spring的quartz定时器同一时刻重复执行二次的问题解决
- linux使用flock文件锁解决脚本重复执行问题
- jquery click嵌套 事件重复注册 多次执行的问题解决
- Spring的quartz定时器同一时刻重复执行二次的问题解决