xxl-job的运行所需要的对象信息在xxl-job_info中,由update_match_state和update_match_step_state两个执行器分别控制赛事状态和赛事阶段状态。
赛事创建时会插入xxl-job所需要的赛事信息
@ApiOperation(value="新增", notes="根据情况新增")
@PostMapping("/save")
@Authority("match:info:add")
@Tracker(value = "赛事新增",operation = "赛事模块")
public CommonResult save(@RequestBody String jsonStr ){
MatchInfoAndStepVO matchInfoAndStepVO = JSONObject.parseObject(jsonStr, MatchInfoAndStepVO.class);
MatchInformationRequest matchInformationRequest=matchInfoAndStepVO.getMatchInformationRequest();
String msg = matchInformationService.save(matchInformationRequest, matchInfoAndStepVO);
try {
this.updateMatchByXxl(matchInfoAndStepVO);
}catch (ParseException e){
throw new BizException("赛事定时任务cron表达式解析异常");
}
通过updateMatchByXxl()方法,代码如下,比赛状态info中报名开始时间为TriggerNextTime,比赛阶段状态中最早的阶段开始时间为TriggerNextTime
private void updateMatchByXxl(MatchInfoAndStepVO matchInfoAndStepVO) throws ParseException {
List<MatchInformation> matchInformations = matchInformationMapper.findByMatchName(matchInfoAndStepVO.getMatchInformationRequest().getMatchName());
if (matchInformations != null && matchInformations.size() == 1){
MatchInformation matchInformation = matchInformations.get(0);
long registerStartTime = matchInformation.getRegisterStartTime().getTime();
String jobDesc = "更新赛事状态任务"+matchInformation.getMatchId();
//更新赛事
insertIntoXxlJob(matchInformation.getMatchId(),registerStartTime,jobDesc,Constant.UPDATE_MATCH_STATE);
//更新step
ArrayList<Long> stepStateTriggerList = getStepStateTriggerList(matchInfoAndStepVO);
Long minTime = Collections.min(stepStateTriggerList);
insertIntoXxlJob(matchInformation.getMatchId(),minTime,"更新赛事阶段状态"+matchInformation.getMatchId(), Constant.UPDATE_MATCH_STEP_STATE);
}
}
insertIntoXxlJob代码如下,设定赛事id、handle执行器、TriggerStatus(1),1为工具启动的状态、TriggerNextTime。
private void insertIntoXxlJob(Integer matchId,Long nextTime,String jobDesc,String handler) throws ParseException {
XxlJobInfo xxlJobInfo = new XxlJobInfo();
xxlJobInfo.setJobGroup(1);
xxlJobInfo.setJobCron(CronUtil.getCronByOnce(new Date(nextTime)));
xxlJobInfo.setJobDesc(jobDesc);
xxlJobInfo.setAddTime(LocalDateTime.now());
xxlJobInfo.setUpdateTime(LocalDateTime.now());
xxlJobInfo.setAuthor("JW");
xxlJobInfo.setExecutorRouteStrategy("FIRST");
xxlJobInfo.setExecutorHandler(handler);
xxlJobInfo.setExecutorParam(matchId.toString());
xxlJobInfo.setExecutorBlockStrategy("SERIAL_EXECUTION");
xxlJobInfo.setExecutorTimeout(1000);
xxlJobInfo.setExecutorFailRetryCount(2);
xxlJobInfo.setGlueType("BEAN");
xxlJobInfo.setGlueRemark("GLUE代码初始化");
xxlJobInfo.setGlueUpdatetime(LocalDateTime.now());
xxlJobInfo.setTriggerStatus(1);
xxlJobInfo.setTriggerLastTime(0L);
xxlJobInfo.setTriggerNextTime(nextTime);
xxlJobInfoMapper.insert(xxlJobInfo);
}
如下为info数据库
如下为两个handle执行器
@XxlJob(Constant.UPDATE_MATCH_STATE)
public ReturnT<String> updateMatchState(String param) throws Exception{
XxlJobLogger.log("开始更新赛事状态");
platformJobManager.updateMatchState(param);
XxlJobLogger.log("赛事状态更新结束");
return ReturnT.SUCCESS;
}
@XxlJob(Constant.UPDATE_MATCH_STEP_STATE)
public ReturnT<String> updateMatchStepState(String param) throws Exception{
XxlJobLogger.log("开始更新赛事阶段状态");
platformJobManager.updateMatchStepState(param);
XxlJobLogger.log("赛事阶段状态更新结束");
return ReturnT.SUCCESS;
举赛事状态handle为栗子,查询info中对应赛事与执行器的info信息,查询赛事中的报名开始、结束,比赛开始、结束的时间,再与当前时间进行比较,分为5个阶段,判断状态、生成cron(时间点的一种表现形式)、TriggerNextTime、TriggerStatus(1)(因为status字段默认0,在更新插入info时,若不设定则为0,则工具停止,到下一阶段则并未启动)。
MatchState handle如下
@Override
public void updateMatchState(String param) throws ParseException {
MatchInformation matchInformation = matchInformationMapper.selectByPrimaryKey(Integer.valueOf(param));
XxlJobInfo xxlJobInfo = xxlJobInfoMapper.selectOne(new LambdaQueryWrapper<XxlJobInfo>().eq(XxlJobInfo::getExecutorParam,param)
.eq(XxlJobInfo::getExecutorHandler,Constant.UPDATE_MATCH_STATE));
if (matchInformation == null){
log.error("找不到对应赛事,match_id = {}",Integer.valueOf(param));
return;
}
long registerStartTime = matchInformation.getRegisterStartTime().getTime();
long registerEndTime = matchInformation.getRegisterEndTime().getTime();
long matchStartTime = matchInformation.getMatchStartTime().getTime();
long matchEndTime = matchInformation.getMatchEndTime().getTime();
long now = System.currentTimeMillis();
if (now < registerStartTime){
matchInformation.setMatchState(1);
xxlJobInfo.setJobCron(CronUtil.getCronByOnce(new Date(registerStartTime)));
xxlJobInfo.setTriggerNextTime(registerStartTime);
xxlJobInfo.setTriggerStatus(1);
}
if (now >= registerStartTime && now < registerEndTime){
matchInformation.setMatchState(2);
xxlJobInfo.setJobCron(CronUtil.getCronByOnce(new Date(registerEndTime)));
xxlJobInfo.setTriggerNextTime(registerEndTime);
xxlJobInfo.setTriggerStatus(1);
}
if (now >= registerEndTime && now < matchStartTime){
matchInformation.setMatchState(3);
xxlJobInfo.setJobCron(CronUtil.getCronByOnce(new Date(matchStartTime)));
xxlJobInfo.setTriggerNextTime(matchStartTime);
xxlJobInfo.setTriggerStatus(1);
}
if (now >= matchStartTime && now < matchEndTime){
matchInformation.setMatchState(4);
xxlJobInfo.setJobCron(CronUtil.getCronByOnce(new Date(matchEndTime)));
xxlJobInfo.setTriggerNextTime(matchEndTime);
xxlJobInfo.setTriggerStatus(1);
}
if (now >= matchEndTime){
matchInformation.setMatchState(5);
xxlJobInfo.setJobCron(CronUtil.getCronByOnce(new Date(matchEndTime)));
xxlJobInfo.setTriggerNextTime(matchEndTime);
xxlJobInfo.setTriggerStatus(0);
}
xxlJobInfo.setUpdateTime(LocalDateTime.now());
xxlJobInfo.setTriggerLastTime(xxlJobInfo.getTriggerNextTime());
matchInformationMapper.updateById(matchInformation);
xxlJobInfoMapper.updateById(xxlJobInfo);
}
MatchStepState handle如下
@Override
public void updateMatchStepState(String param) throws ParseException {
List<MatchStep> matchStep = matchStepMapper.selectList(new LambdaQueryWrapper<MatchStep>().eq(MatchStep::getMatchId,Integer.valueOf(param)));
XxlJobInfo xxlJobInfo = xxlJobInfoMapper.selectOne(new LambdaQueryWrapper<XxlJobInfo>().eq(XxlJobInfo::getExecutorParam,param)
.eq(XxlJobInfo::getExecutorHandler,Constant.UPDATE_MATCH_STEP_STATE));
if (matchStep == null || matchStep.size() == 0){
log.error("找不到对应赛事,match_id = {}",Integer.valueOf(param));
return;
}
long now = System.currentTimeMillis();
for (MatchStep step : matchStep){
long startTime = step.getStartTime().getTime();
long endTime = step.getEndTime().getTime();
if (step.getMatchStep().equals(3)){
continue;
}
if (now < startTime){
step.setMatchStepState(1);
xxlJobInfo.setJobCron(CronUtil.getCronByOnce(new Date(startTime)));
xxlJobInfo.setTriggerNextTime(startTime);
xxlJobInfo.setTriggerStatus(1);
}
if (now >= startTime && now < endTime){
step.setMatchStepState(2);
xxlJobInfo.setJobCron(CronUtil.getCronByOnce(new Date(endTime)));
xxlJobInfo.setTriggerNextTime(endTime);
xxlJobInfo.setTriggerStatus(1);
}
if (now >= endTime){
step.setMatchStepState(3);
xxlJobInfo.setJobCron(CronUtil.getCronByOnce(new Date(endTime)));
xxlJobInfo.setTriggerNextTime(endTime);
// 最后一个阶段过后 stop触发器
if(matchStep.size() - 1 == matchStep.indexOf(step)){
xxlJobInfo.setTriggerStatus(0);
}else {
xxlJobInfo.setTriggerStatus(1);
}
}
xxlJobInfo.setUpdateTime(LocalDateTime.now());
xxlJobInfo.setTriggerLastTime(xxlJobInfo.getTriggerNextTime());
matchStepMapper.updateById(step);
xxlJobInfoMapper.updateById(xxlJobInfo);
}
大致逻辑为:赛事创建和更新时会同时更新xxl-info的数据库的对应信息(cron和TriggerNextTime为下次状态更新时间,两个handle分别控制赛事状态和赛事阶段状态),到了对应时间,xxl-job组件内的handle执行器将执行各自任务对状态进行更新,更新后刷新下次更新需要的info。
如下为赛事修改
@ApiOperation(value="修改", notes="根据情况修改")
@PostMapping("/update")
@Authority("match:info:update")
@Tracker(value = "赛事修改",operation = "赛事模块")
public CommonResult update(@RequestBody String jsonStr){
MatchInfoAndStepVO matchInfoAndStepVO = JSONObject.parseObject(jsonStr, MatchInfoAndStepVO.class);
MatchInformationRequest matchInformationRequest=matchInfoAndStepVO.getMatchInformationRequest();
List<MatchStepRequest> matchStepRequests = matchInfoAndStepVO.getMatchStepRequests();
matchInformationService.update(matchInformationRequest,matchStepRequests);
try {
this.updateXxl(matchInfoAndStepVO);
}catch (ParseException e){
throw new BizException("赛事定时任务cron表达式解析异常");
}
return ResultUtil.success(ResultCode.SUCCESS);
}
updatexxl,查询修改的赛事信息,并将信息时间与下次更新时间进行比较判定,修改下次更新时间。
/**
* 更新触发定时任务时间
*/
private void updateXxl(MatchInfoAndStepVO matchInfoAndStepVO) throws ParseException {
MatchInformation matchInformation = null;
if (matchInfoAndStepVO.getMatchInformationRequest().getMatchId() != null){
matchInformation = matchInformationMapper.selectByPrimaryKey(matchInfoAndStepVO.getMatchInformationRequest().getMatchId());
}else {
matchInformation = matchInformationMapper.findByMatchName(matchInfoAndStepVO.getMatchInformationRequest().getMatchName()).get(0);
}
ArrayList<Long> matchStateTriggerList = getMatchStateTriggerList(matchInfoAndStepVO);
ArrayList<Long> stepStateTriggerList = getStepStateTriggerList(matchInfoAndStepVO);
long now = System.currentTimeMillis();
XxlJobInfo match = xxlJobInfoMapper.selectOne(new LambdaQueryWrapper<XxlJobInfo>().eq(XxlJobInfo::getExecutorParam,matchInformation.getMatchId()).eq(XxlJobInfo::getExecutorHandler,Constant.UPDATE_MATCH_STATE));
XxlJobInfo matchStep = xxlJobInfoMapper.selectOne(new LambdaQueryWrapper<XxlJobInfo>().eq(XxlJobInfo::getExecutorParam,matchInformation.getMatchId()).eq(XxlJobInfo::getExecutorHandler,Constant.UPDATE_MATCH_STEP_STATE));
long thisMatchTime = match.getTriggerLastTime();
long thisMatchStepTime =matchStep.getTriggerNextTime();
for (Long aLong : matchStateTriggerList) {
if (now < aLong && aLong < match.getTriggerNextTime()){
match.setTriggerNextTime(aLong);
}
}
if (match.getTriggerNextTime() != thisMatchTime){
match.setJobCron(CronUtil.getCronByOnce(new Date(match.getTriggerNextTime())));
xxlJobInfoMapper.updateById(match);
}
for (Long aLong : stepStateTriggerList) {
if (now < aLong && aLong < matchStep.getTriggerNextTime()){
matchStep.setTriggerNextTime(aLong);
}
}
if (matchStep.getTriggerNextTime() != thisMatchStepTime){
matchStep.setJobCron(CronUtil.getCronByOnce(new Date(matchStep.getTriggerNextTime())));
xxlJobInfoMapper.updateById(matchStep);
}