「这是我参与2022首次更文挑战的第8天,活动详情查看:2022首次更文挑战」
1、前言
上一篇的分享中,我为大家分享了在SpringBoot项目中基于Quartz开发定时任务的简单实现及简单的封装。但是,现在的应用基本上很少是单体项目了,都根据不同维度将系统拆分成了微服务应用。那么本篇为大家介绍如何在微服务项目中开发定时任务。
2、微服务项目中定时任务的实现
从单体应用拆分成微服务应用,大体上都是根据业务来划分成不同的服务,尽可能地让每一种独立的业务在一个服务中进行处理。在这种情况下,对于定时任务的处理,一种是让每一个服务维护自己的定时任务,另一种是在公共服务里维护定时任务。执行任务时,对具体的任务进行http远程调用来实现。这种解决方案其实并不太好,特别是在分布式环境下不是很可靠,但实现起来很简单。下面就为大家分享下具体代码:
//管理定时任务的Controller
public class QuartzController extends BaseController {
//启动一个任务
@RequestMapping("/startTask.json")
@ResponseBody
public String startTask() {
Map<String, Object> map =RequestSupport.getParameters();
String id=String.valueOf(map.get("id"));
String jobname=String.valueOf(map.get("jobname"));
StringBuilder logInfo = new StringBuilder();
logInfo.append("任务事件:开启任务").append("\n");
logInfo.append("请求服务器:").append(BaseBeansConfig.HostPort).append("\n");
if (!ScheduleJobInit.getIsRuunning()){
try {
String serverAddress = getDoJobCacheAddress();
String url = "http://"+serverAddress+"/startTask.json";
logInfo.append("处理结果:请求的服务器没有执行权限,正请求服务:").append(url).append("\n");
String QUARTZRECORD = quartzBiz.addTaskLog(id,jobname,logInfo.toString());
map.put("QUARTZRECORD",QUARTZRECORD);
HttpRequester requester = new HttpRequester();
HttpRespons httpRespons=requester.sendPost(url , map);
return httpRespons.getContent();
} catch (Exception e) {
e.printStackTrace();
return updateFailure(e.getMessage());
}
}
logInfo.append("处理结果:请求的服务器有执行权限").append("\n");
try {
if (map.get("QUARTZRECORD")==null) {
String QUARTZRECORD=quartzBiz.addTaskLog(id , jobname , logInfo.toString());
map.put("QUARTZRECORD" , QUARTZRECORD);
}
quartzBiz.startTask(map);
} catch (MySchedulerException e) {
return updateFailure(e.getMessage());
}
return updateSuccess();
}
//暂停一个任务
@RequestMapping("/pauseTask.json")
@ResponseBody
public String pauseTask() throws MySchedulerException{
//代码与开始定时任务类似...
}
}
//定时任务业务处理类
public class QuartzBiz {
//这里、将每一个有权限执行定时任务的服务器ip存在了redis里面,执行任务前,会先去判断是否具有执行权限
@Resource
private RedisPublishHandler redisPublishHandler;
public void startTask (Map<String,Object> map) throws MySchedulerException {
QuartzInfo quartzInfo=new QuartzInfo();
quartzInfo.setId(Integer.parseInt(String.valueOf(map.get("id"))));
quartzInfo.setJobName(getStrByObj(map.get("jobname")));
quartzInfo.setServiceName(getStrByObj(map.get("servicename")));
quartzInfo.setServiceUrl(getStrByObj(map.get("serviceurl")));
quartzInfo.setCronExpression(getStrByObj(map.get("cronexpression")));
//前置任务id,支持多个,以逗号【","】分割
String preTaskId=getStrByObj(map.get("pretaskid"));
quartzInfo.setPreTaskIds(preTaskId);
quartzInfo.setPreJobs(getpreInfoById(preTaskId));
quartzInfo.setDoAll(getStrByObj(map.get("doall")));
CronTrigger cronTrigger=QuartzUtil.getCronTrigger(scheduler , quartzInfo.getJobName());
String id=String.valueOf(quartzInfo.getId());
if (cronTrigger == null) {
//创建一个新的任务
QuartzUtil.creatSchedulerJob(scheduler , quartzInfo);
quartzDao.changeStatus(id , "1");
} else {
// Trigger已存在,那么更新相应的定时设置
QuartzUtil.deleteTask(scheduler , quartzInfo.getJobName());
//QuartzUtil.updateTask(scheduler, quartzInfo);
QuartzUtil.creatSchedulerJob(scheduler , quartzInfo);
quartzDao.changeStatus(id , "1");
}
executeTaskLog(String.valueOf(map.get("QUARTZRECORD")),String.valueOf(quartzInfo.getId()),"\n执行成功","1");
flushTaskGrid();
}
//由于接收请求的服务器不一定就是任务执行服务器,所以列表的刷新存在延迟,这里使用websocket发送刷新请求
private void flushTaskGrid() {
try {
redisPublishHandler.publish(RedisPublishConfig.reloadTaskGrid, null, "reload");
} catch (Exception e) {
e.printStackTrace();
}
}
public void pauseTask (Map<String,Object> map) throws MySchedulerException {
String id=getStrByObj(map.get("id"));
String jobName=getStrByObj(map.get("jobName"));
QuartzUtil.pauseSchedulerJob(scheduler , jobName );
quartzDao.changeStatus(id , "0");
executeTaskLog(String.valueOf(map.get("QUARTZRECORD")),id,"\n执行成功","1");
flushTaskGrid();
}
@Transactional(propagation=Propagation.REQUIRES_NEW, rollbackFor=Exception.class)
public void deleteTask (Map<String,Object> map) throws MySchedulerException {
String jobName=getStrByObj(map.get("jobName"));
String id=getStrByObj(map.get("id"));
QuartzUtil.deleteTask(scheduler , jobName);
quartzDao.deleteTask(id);
quartzDao.deleteTaskLog(id);
executeTaskLog(String.valueOf(map.get("QUARTZRECORD")),id,"\n执行成功","1");
flushTaskGrid();
}
public void jobInit () throws MySchedulerException {
List<Map<String, String>> listMaps=quartzDao.getStartTask();
if (CollectionUtils.isEmpty(listMaps)) {
return;
}
for (Map<String, String> map : listMaps) {
String jobName=map.get("jobName");
String servicename=map.get("servicename");
String serviceurl=map.get("serviceurl");
String cronExpression=map.get("cronexpression");
String preTaskId=map.get("pretaskid");
String doAll=map.get("doall");
QuartzInfo quartzInfo=new QuartzInfo();
quartzInfo.setJobName(jobName);
quartzInfo.setServiceName(servicename);
quartzInfo.setServiceUrl(serviceurl);
quartzInfo.setCronExpression(cronExpression);
quartzInfo.setPreTaskIds(preTaskId);
quartzInfo.setPreJobs(getpreInfoById(preTaskId));
quartzInfo.setDoAll(doAll);
//在Scheduler获取触发器对象
CronTrigger cronTrigger=QuartzUtil.getCronTrigger(scheduler , jobName);
if (cronTrigger == null) {
//创建一个新任务
QuartzUtil.creatSchedulerJob(scheduler , quartzInfo);
} else {
QuartzUtil.deleteTask(scheduler , jobName);
QuartzUtil.creatSchedulerJob(scheduler , quartzInfo);
}
}
}
}
好了、本期就先介绍到这里,有什么需要交流的,大家可以随时私信我。😊