大家好~我是米洛

我正在从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. 我只启动1个worker

有点傻,而且性能不好使,多台机器部署依然有问题。

推荐指数: 0颗星

  1. 初始化sceduler的时候,利用socket占据一个固定的端口比如2333

端口号只能被1个worker占领,其他worker拿不到,也就起不来了。但还是不能支持多节点部署,实际上只有1个worker使用,浪费了1个端口

推荐指数:

  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语句,敬请期待吧。

测试平台系列(82) 解决APScheduler重复执行的问题的更多相关文章

  1. Pytest系列(十三)- 重复执行之pytest-repeat的使用

    写在前面 这个插件,可以帮助我们很好的解决自动化测试过程中的一些偶线性bug难以复现的问题,但前提是,当前自动化脚本是独立的,不依赖任何其他脚本.个人觉得还是失败重运行的一种体现,就和TestNG是一 ...

  2. Pytest系列(13)- 重复执行用例插件之pytest-repeat的详细使用

    如果你还想从头学起Pytest,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1690628.html 前言 平常在做功能测试的时候,经常 ...

  3. 测试平台系列(5) 引入Ant Design Pro

    引入Ant Design Pro 回顾 还是继续回顾下之前的作业, 返回的中文变成了ascii字符,不要紧,我们光荣地百度一哈. 随便点进去看看,都可以找到正确答案: 可以看到,我们需要修改confi ...

  4. 测试平台系列(4) 使用Flask蓝图(blueprint)

    使用Flask蓝图(blueprint) 回顾 先来看一下上一篇的作业吧,使用「logbook」的时候,遇到了时区不对的情况.那么我们怎么去解决这个问题呢? 实际上logbook默认采用的是世界标准时 ...

  5. 测试平台系列(1) 搭建Flask服务

    搭建Flask服务 项目地址 点我进入项目地址 代码都会在这里有所展示,喜欢的话可以帮点个star,谢谢大家了!如果你喜欢该教程,也可以分享给其他人. 关于选型 想了很久,本来打算用「Gin」做为后端 ...

  6. 测试平台系列(2) 给Pity添加配置

    给Pity添加配置 回顾 还记得上篇文章创立的「Flask」实例吗?我们通过这个实例,给根路由 「/」 绑定了一个方法,从而使得用户访问不同路由的时候可以执行不同的方法. 配置 要知道,在一个「Web ...

  7. 测试平台系列(3) 给Hello World添加日志

    给Hello World添加日志 回顾 通过上篇内容,我们已经使用「Flask」完成了我们的第一个接口.我们可以看到,使用「Flask」来编写接口是十分简单的.那么接下来,我们丰富一下上面的例子. 需 ...

  8. 如何解决 shell 脚本重复执行的问题

    在开发过程中,经常会使用shell脚本去完成定时备份的任务,普遍的做法是通过系统的定时任务定时执行备份脚本 设想这样一种场景,本次备份时间到了,自动执行备份脚本,如果备份比较耗时的话,会一直持续到下一 ...

  9. Spring+quartz集群解决多服务器部署定时器重复执行的问题

    一.问题描述 Spring自带的Task虽然能很好使用定时任务,只需要做些简单的配置就可以了.不过如果部署在多台服务器上的时候,这样定时任务会在每台服务器都会执行,造成重复执行. 二.解决方案 Spr ...

  10. 解决Spring Security自定义filter重复执行问题

    今天做项目的时候,发现每次拦截器日志都会打两遍,很纳闷,怀疑是Filter被执行了两遍.结果debug之后发现还真是!记录一下这个神奇的BUG! 问题描述 项目中使用的是Spring-security ...

随机推荐

  1. Linux文件系统扩容步骤

    1 扩容前检查 cat /etc/fstab df -h 在扩容之前请确认VG的Free大小,以及文件和文件系统是否达到系统限制 2 系统识别硬盘 #echo "- - -" &g ...

  2. Android 常用布局视图

    常用包 http://square.github.io/ EventBus Scroller 滚动 拖拽 # android.support.design.widget.CollapsingToolb ...

  3. 1 Ionic和Hybird应用介绍

    1.Ionic是什么,它和Angular.Cordova有什么关系? Ionic通过整合各种技术和功能使构建Hybird应用更加快速.容易和美观.Ionic生态系统基于Angular和Cordova, ...

  4. python 继承基础

    class annamal: def chi(self): print(self.name + '吃') def he(self): print(self.name + '喝') class dog( ...

  5. linux驱动简单介绍

     linux驱动简单介绍 驱动基本介绍 驱动.顾名思义就是“驱使硬件设备行动”.设备驱动与底层硬件之间打交道,按照硬件设备的具体操作方式来读写设备寄存器,最终完成一系列操作. 设备 驱动充当了应用程序 ...

  6. JS JSON对象相关

    1.多对象合并 将2个或2个以上对象(object{....})中的属性进行合并,即最后合并为一个object{.....} 解决办法:Object.assign 方法 var form = {nam ...

  7. ionic3 实现扫码功能

    ionic3 通过插件phonegap-plugin-barcodescanner,调用机器硬件摄像头实现扫码功能. 首先当然先了解下 phonegap-plugin-barcodescanner,这 ...

  8. 03 字符串常用操作方法及For 循环

    字符串常用操作 s = 'alexWUsir' s1 = s.capitalize() #首字母大写 print(s1) #Alexwusir s2 = s.upper() #全部大写 print(s ...

  9. IntelliJ IDEA工具的安装使用

    一:解压,到目录E:\IDEA\bin下,本机是64位,就点击idea64.exe,如下: 二:注册码获取地址:http://idea.lanyus.com/.如图: 将此注册码复制到上图中去. 三: ...

  10. centos下配置DNS

    centos网络配置实例 1,配置DNSvi /etc/resolv.conf加入: 代码如下: nameserver 192.168.0.1 nameserver 8.8.8.8 nameserve ...