Reprint: https://blog.csdn.net/menghuanzhiming/article/details/77744267
Task requirements:
Close overtime unpaid orders and invalidate order information
Related technologies:
Quatz Framework Timing Scheduling
- Realization ideas:
1. When the service starts, query the order data in the database which has not been paid for, and store the order in the queue one after another according to the time of the order. First, save the order until the end of the queue, then store the order at the end of the queue, and take the first element of the queue.
2. Detection and current time, if more than 40 minutes, then perform data operations, that is, close the order, but only close the unpaid order, then remove the header element from the queue, and take the next element for detection, and so on.
3. If the detection time is less than 40 minutes, the thread waits for the corresponding time difference and then executes the order operation.
Relevant issues:
1. To prevent polling tasks from reaching the end, that is, to start the next polling when the last job has not finished. The solution is to add the @DisallowConcurrent Execution annotation on the job, which is to make the next job wait for the current job to finish.
2. Setting polling interval is 35 minutes, order timeout is 40 minutes, there is a 5-minute time difference between them. In order to prevent the order from being added to the queue many times, we should pay attention to the weight when joining the order queue.
Relevant code
Mode 1: Monitor + quartz implementation;
package com.taotao.order.scheduler; import org.apache.log4j.Logger; import org.quartz.CronScheduleBuilder; import org.quartz.CronTrigger; import org.quartz.JobBuilder; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.SchedulerFactory; import org.quartz.Trigger; import org.quartz.TriggerBuilder; import org.quartz.impl.StdSchedulerFactory; import com.taotao.order.controller.OrderController; /** * * @ClassName: CancelOrderTask * @Description: TODO(Cancellation order execution class) * @author * @date 2017 September 1, 10:58:26 a.m. * */ public class CancelOrderTask { static Logger logger = Logger.getLogger(OrderController.class); /* * 1 Two job configurations with two triggers */ public void cancelOrderTask() throws SchedulerException { // Get a scheduler SchedulerFactory schedulerFactory = new StdSchedulerFactory(); Scheduler scheduler = schedulerFactory.getScheduler(); // Create a job task name, task group, task execution class JobDetail jobDetail = JobBuilder.newJob(CancelOrderJob.class) .withIdentity("cancelOrderJob", "orderJob") //Setting job's name and group .storeDurably() //When job does not bind triggers, putting scheduler does not throw exceptions .build(); scheduler.addJob(jobDetail, false); //Create a simple trigger that executes immediately when the project is started. CronTrigger's startNow() method does not work after setting a timed task. Trigger simpleTrigger = TriggerBuilder.newTrigger() .withIdentity("firstCancelOrderTrigger", "firstOrderTrigger") //Setting trigger name and group .startNow() //Setting for immediate execution .forJob("cancelOrderJob", "orderJob") //Trigger binding job .build(); //Trigger added to scheduler scheduler.scheduleJob(simpleTrigger); /* * Create a CronTrigger trigger to set the trigger time * CronTrigger The trigger startNow doesn't work because it has its own trigger time. */ CronTrigger cronTrigger = TriggerBuilder.newTrigger() .withIdentity("cancelOrderTrigger", "orderTrigger") .withSchedule(CronScheduleBuilder.cronSchedule("0 0/2 * * * ?")) //Trigger time (polling time) .forJob("cancelOrderJob", "orderJob").build(); //Trigger binding job // Bind job to trigger scheduler.scheduleJob(cronTrigger); String logInfo = jobDetail.getKey() + "Cancel Order Task Timer Start"; logger.info(logInfo); System.out.println(logInfo); scheduler.start(); } public static void main(String[] args) { CancelOrderTask cancelOrderTask = new CancelOrderTask(); try { cancelOrderTask.cancelOrderTask(); } catch (SchedulerException e) { e.printStackTrace(); } } }
The job of the quartz task, which detects and closes a database invalid order, is coded as follows:
package com.nice.util.quartz; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; import com.nice.dao.ValarmDataInfoMapper; import com.nice.model.ValarmDataInfo; import com.nice.service.AlarmDataService; import org.apache.log4j.Logger; import org.quartz.DisallowConcurrentExecution; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.spi.TriggerFiredBundle; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.stereotype.Service; import org.springframework.web.context.support.SpringBeanAutowiringSupport; import javax.annotation.Resource; /** * quartz Task job to detect and close database invalid orders * @DisallowConcurrentExecution This annotation indicates that if the last task is not completed, the next one will not be performed. */ @DisallowConcurrentExecution @Component public class CancelOrderJob implements Job { @Autowired private AlarmDataService service; //Order validity time 40 minutes public static final long EFFTIVE_TIME = 3 * 60 * 1000; private Logger logger = Logger.getLogger(CancelOrderJob.class); @Override public void execute(JobExecutionContext arg0) throws JobExecutionException { //The following line of code must be added, otherwise it will not be able to inject beans, which will report a null pointer error. SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this); System.out.println("Initiation of Failure Order Detection Task!"); Queue<ValarmDataInfo> queue = new LinkedList<>(); // Search the database for invalid orders each time Job is started and join the queue (query from the database, use false data here) List<ValarmDataInfo> list = service.queryAll(); System.out.println("list Size:"+list.size()); if (!list.isEmpty()) { for (ValarmDataInfo o : list) { queue.offer(o); } } // Get the header element of the queue and start checking if the header order is invalid ValarmDataInfo element = queue.peek(); System.out.println("element="+element); while (element != null) { //Time difference Long diff = this.checkOrder(element); if (diff != null && diff >= EFFTIVE_TIME) { System.out.println("Start closing orders" + element.getDevicename() + "Order time" + element.getAlarmstarttime()); // Ejection queue queue.poll(); // Take the next element element = queue.peek(); } else if (diff < EFFTIVE_TIME) { try { System.out.println("Waiting for Inspection Order" + element.getDevicename() + "Order time" + element.getAlarmstarttime() + "Order has been placed" + diff / 1000 + "second"); //Thread Waiting Thread.sleep(EFFTIVE_TIME - diff); } catch (InterruptedException e) { e.printStackTrace(); logger.info("CancelOrderJob.checkOrder Timing Task Problem"); } } } } /** * Get the order time and the current time difference * * @author wangpeiqing 2016 April 16, 2001 * @param order * @return * */ public Long checkOrder(ValarmDataInfo order) { Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Long diff = null; if (order != null) { Date createTime = order.getAlarmstarttime(); try { diff = sdf.parse(sdf.format(date)).getTime() - sdf.parse(sdf.format(createTime)).getTime(); } catch (ParseException e) { e.printStackTrace(); } } // The return value is milliseconds return diff; } }
Monitor class
package com.taotao.order.listener; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import org.quartz.SchedulerException; import com.taotao.order.scheduler.CancelOrderTask; public class CancelOrderListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { CancelOrderTask task = new CancelOrderTask(); try { task.cancelOrderTask(); } catch (SchedulerException e) { e.printStackTrace(); } } @Override public void contextDestroyed(ServletContextEvent sce) { } }
Configuration listener: Adding listeners to web.xml files to perform execution tasks when starting programs
<! - Cancel the order listener and execute the execution task when starting the program - > <listener> <listener-class>com.taotao.order.listener.CancelOrderListener</listener-class> </listener>