“This is the 8th day of my participation in the First Challenge 2022. For details: First Challenge 2022”

1, the preface

In my last post, I shared a simple implementation and encapsulation of timed tasks based on Quartz in the SpringBoot project. However, today’s applications are rarely monolithic projects, breaking up systems into microservice applications based on different dimensions. This article shows you how to develop scheduled tasks in a microservice project.

2. Implementation of scheduled tasks in micro-service projects

The separation of single application into micro-service application is basically divided into different services according to business, so that each kind of independent business can be processed in one service as much as possible. In this case, to deal with scheduled tasks, one way is to let each service maintain its own scheduled task, the other way is to maintain scheduled tasks in the public service. When a task is executed, HTTP remote calls are made to a specific task. This solution isn’t very good, especially in a distributed environment, but it’s easy to implement. Here is the specific code to share with you:

 // Manage the Controller of scheduled tasks
public class QuartzController extends BaseController { 
	 
    // Start a task
	@RequestMapping("/startTask.json")
	@ResponseBody
	public  String  startTask(a) {
		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("Task Event: Start task").append("\n");
		logInfo.append("Request server:").append(BaseBeansConfig.HostPort).append("\n");
		if(! ScheduleJobInit.getIsRuunning()){try {
				String serverAddress = getDoJobCacheAddress();
				String url = "http://"+serverAddress+"/startTask.json";
				logInfo.append("Result: requested server has no execute permission and is requesting service:").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("Processing result: requested server has execute permission").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();
		
	} 
    
    // Pause a task
	@RequestMapping("/pauseTask.json")
	@ResponseBody
	public String pauseTask(a) throws MySchedulerException{
		// The code is similar to starting a scheduled task...}}// Scheduled task business processing class
public class QuartzBiz {
    
    // Save the IP address of each server that has the permission to execute scheduled tasks in redis. Before executing tasks, check whether the server has the permission to execute tasks
	@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")));
        // Task ID. Multiple tasks can be separated by commas (",")
		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) {
			Create a new task
			QuartzUtil.creatSchedulerJob(scheduler , quartzInfo);
			quartzDao.changeStatus(id , "1");
		} else {
			// Trigger already exists, then update the corresponding timing setting
			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 Execution successful"."1");
		flushTaskGrid();
	}

	// Since the server receiving the request is not necessarily the task execution server, there is a delay in refreshing the list
	private void flushTaskGrid(a) {
		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 Execution successful"."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 Execution successful"."1");
		flushTaskGrid();
	}  

	public void jobInit (a) 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);
			// Fetch the trigger object from Scheduler
			CronTrigger cronTrigger=QuartzUtil.getCronTrigger(scheduler , jobName);
			if (cronTrigger == null) {
				// Create a task
				QuartzUtil.creatSchedulerJob(scheduler , quartzInfo);
			} else{ QuartzUtil.deleteTask(scheduler , jobName); QuartzUtil.creatSchedulerJob(scheduler , quartzInfo); }}}}Copy the code

Well, this period will be introduced here first, what need to communicate, we can at any time private letter I. 😊