任务需求:
关闭超时未支付的订单,将订单信息置为失效状态
相关技术:
quartz框架定时调度
实现思路:
- 在服务启动时,查询数据库中的已下单未支付的订单数据,按下单时间先后存入队列中,先下单的存到头不,后下单存入队列尾部,取队列的头元素
- 检测与现在的时间,如果超过40分钟,则执行数据操作,即关闭订单,但是只关闭未支付的订单,之后在将头元素从队列移出,并取出下一个元素进行检测,以此类推
- 如果检测出时间未到40分钟,则线程等待相应的时间差,之后在执行订单操作
相关问题:
- 在执行时要防止轮询任务追尾,即在上一个job未执行完毕时就开始下一次轮询,解决方法是在job上加@DisallowConcurrentExecution注解,该注解的作用是让下一次job要等待当前job执行完毕
- 设置的轮询间隔是35分钟一次,订单超时是4分钟,中间有5分钟的时间差,为了防止订单被多次加入队列中,在加入订单队列时要注意去重
相关代码
package com.ichunshen.dolook.module.trade.order.support; import static org.quartz.CronScheduleBuilder.cronSchedule; import static org.quartz.JobBuilder.newJob; import static org.quartz.TriggerBuilder.newTrigger; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import org.apache.log4j.Logger; import org.quartz.CronTrigger; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.SchedulerFactory; import org.quartz.impl.StdSchedulerFactory; import com.ichunshen.dolook.module.trade.order.job.CancelOrderJob; import com.ichunshen.dolook.module.trade.order.model.Order; import com.ichunshen.dolook.module.trade.order.web.OrderController; public class CancelOrderTask { static Logger logger = Logger.getLogger(OrderController.class); public void cancelOrderTask() throws SchedulerException { // 获得一个scheduler SchedulerFactory sh = new StdSchedulerFactory(); Scheduler scheduler = sh.getScheduler(); // 创建一个job 任务名,任务组,任务执行类 JobDetail job = newJob(CancelOrderJob.class).withIdentity("cancelOrderJob", "orderJob").build(); //创建一个触发器 CronTrigger trigger = newTrigger().withIdentity("cancelOrderTrigger", "orderTrigger") .withSchedule(cronSchedule("0 0/2 * * * ?")).build(); //将job和触发器绑定 Date date=scheduler.scheduleJob(job, trigger); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS"); logger.info(job.getKey()+"取消订单定时任务于"+sdf.format(date)+"开始执行"); scheduler.start(); } }
package com.ichunshen.dolook.module.trade.order.job; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import org.apache.log4j.Logger; import org.quartz.DisallowConcurrentExecution; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.PersistJobDataAfterExecution; import org.quartz.StatefulJob; import com.ichunshen.dolook.module.trade.order.model.Order; import com.ichunshen.dolook.module.trade.order.service.OrderService; import com.ichunshen.dolook.module.trade.order.support.OrderQueue; import com.ichunshen.dolook.support.DoLookConstant.OrderCancelMethod; import cn.joy.framework.plugin.quartz.ScheduleTask; /** * quartz任务的job,用于检测数据库失效订单并将其关闭 * @author wangpeiqing * */ @DisallowConcurrentExecution public class CancelOrderJob implements ScheduleTask { Logger logger=Logger.getLogger(CancelOrderJob.class); @Override public void execute(JobExecutionContext arg0) throws JobExecutionException { // TODO Auto-generated method stub System.out.println("失效订单检测任务开始执行!"); Order order =new Order(); OrderQueue queue = new OrderQueue(); //在每次启动Job时去数据库查找失效订单,并加入到队列中 List<Order> list=order.getInvalidOrder(); if(!list.isEmpty()){ for (Order o : list) { queue.offer(o); } } //获取队列的头元素,开始检测头订单是否失效 Order element=queue.peek(); while (element!=null) { Long time=this.checkOrder(element); if (time != null && time >=2400*1000) { System.out.println("开始关闭订单"+element.getOcode()+"下单时间"+element.getOrderTime()); element.cancelInvalidOrderStatus(element.getOcode(), OrderCancelMethod.INVALID_TIME); queue.poll(); element=queue.peek(); }else if(time<2400*1000){ try { System.out.println("等待检测订单"+element.getOcode()+"下单时间"+element.getOrderTime()+"已下单"+time/1000+"秒"); Thread.sleep(time); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); logger.info("CancelOrderJob.checkOrder定时任务出现问题"); } } } } /** * 获取订单的下单时间和现在的时间差 * @author wangpeiqing * 2016年4月16日 * @param order * @return * */ public Long checkOrder(Order order) { Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); OrderQueue queue = new OrderQueue(); Long diff = null; if (order != null) { Date orderTime = order.getOrderTime(); try { diff = sdf.parse(sdf.format(date)).getTime() - sdf.parse(sdf.format(orderTime)).getTime(); } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //返回值为毫秒 return diff; } }
package com.ichunshen.dolook.module.trade.order.support; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import org.quartz.SchedulerException; public class CancelOrderListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { // TODO Auto-generated method stub CancelOrderTask task = new CancelOrderTask(); try { task.cancelOrderTask(); } catch (SchedulerException e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override public void contextDestroyed(ServletContextEvent sce) { // TODO Auto-generated method stub } }
时间: 2024-10-09 11:02:52