1、问题背景
脚本任务下关联了一批用例,脚本任务执行会把用例发送到执行器执行。执行器执行任务,并将其中的每个用例执行结果通过http请求回传到研测平台。数据平台对测试结果进行统计,计算已经执行了多少用例,成功多少,失败多少,并在任务执行完成后,发送运行结果通知给对应的执行人。由于用例是单个结果回传,就会出现如下图显示的并发问题:两个运行结果相同的用例几乎同时到达研测中心,各自从数据库读取任务执行日志,然后passCount(记录成功用例数),failCount(记录失败用例数)自增,然后入库测试任务日志的方式,就存在结果覆盖的问题,导致数据不对。

2、解决方案
对于并发问题,很容易就能想到可以通过“同步”方式解决。
解决方法:
1、测试结果统计的方法加上synchronized修饰,将方法变成同步方法。在进入synchronized修饰的方法时,需要获取对象锁。
2、在任务执行时,将任务总的用例数totalCaseCount存入redis中,key为taskLogId。并借助redis的自增方法incr,设置failCountKey统计失败用例数,passCountKey统计成功用例数,初始值为0。
3、在结果回传统计方法中,如果用例失败,则failCountKey自增1,如果用例成功,则passCountKey自增1。然后校验成功用例+失败用例数是否等于任务总的用例数。如果相等,说明任务执行完成。
期间还是遇到了偶现的并发问题。后经排查,发现@Transactional 和synchronized一起使用存在线程安全问题,如下图。同步方法被事务包围,当其中的同步方法执行完成后,锁就被释放,其他线程就可以进入同步方法。但在此期间,可能事务还未提交,导致读取的数据事务提交前的。

【解决方法】:将同步方法放在事务之上。
/**
* 用例结果回传
*
* @param result
*/
public synchronized void caseRunResultCallBack(PyCaseRunResultDTO result) {
// 校验参数
checkCallBackParams(result);
setCaseRunLog(result);
}
@Transactional(rollbackFor = Exception.class)
public void setTestCaseRunLog(PyCaseRunResultDTO result) {
// 统计用例执行结果
}
具体可以参考博客:
https://zhuanlan.zhihu.com/p/56961571
脚本任务执行时,用例单个结果回传会出现并发问题,导致数据覆盖。解决方案是将测试结果统计方法设为同步方法,借助redis自增方法统计用例数。但使用@Transactional和synchronized时存在线程安全问题,需将同步方法放在事务之上。


被折叠的 条评论
为什么被折叠?



