標籤:
任務需求:
關閉逾時未支付的訂單,將訂單資訊置為失效狀態
相關技術:
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 * */@DisallowConcurrentExecutionpublic 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 }}
電子商務平台自動取消失效訂單