訂單超時自動取消,延時任務
阿新 • • 發佈:2019-01-10
應用場景,電商專案使用者下單後超過指定時間未支付,訂單自動失效。
使用延時佇列會使用到定時任務,需要先把定時任務做好。
在使用者下單成功後。定時任務定時掃描出下單成功且未支付的訂單,將訂單加入到延時執行佇列中。同時也加入到快取中。
延時執行類在執行訂單失效時,先到快取內查詢一次,如果沒有查詢到,說明該訂單已支付或者已取消(支付成功或取消訂單清除對應快取)
一;執行實體
package io.jboot.admin.job; import java.util.concurrent.Delayed; import java.util.concurrent.TimeUnit; import com.hnzh.wmall.service.entity.IndentCommodity; public class TaskEntity implements Delayed{ private int id; private String body; //訊息內容 private IndentCommodity indentCommodity; private long excuteTime;//執行時間 public String getBody() { return body; } public void setBody(String body) { this.body = body; } public long getExcuteTime() { return excuteTime; } public void setExcuteTime(long excuteTime) { this.excuteTime = excuteTime; } public TaskEntity(int id, String body,long delayTime) { this.id = id; this.body = body; this.excuteTime = TimeUnit.NANOSECONDS.convert(delayTime, TimeUnit.MILLISECONDS) + System.nanoTime(); } public TaskEntity(int id, IndentCommodity indentCommodity,long delayTime) { this.id = id; this.indentCommodity = indentCommodity; this.excuteTime = TimeUnit.NANOSECONDS.convert(delayTime, TimeUnit.MILLISECONDS) + System.nanoTime(); } public TaskEntity(int id, long delayTime) { this.id = id; this.excuteTime = TimeUnit.NANOSECONDS.convert(delayTime, TimeUnit.MILLISECONDS) + System.nanoTime(); } @Override public int compareTo(Delayed delayed) { TaskEntity msg = (TaskEntity)delayed; return Integer.valueOf(this.id)>Integer.valueOf(msg.id)?1:( Integer.valueOf(this.id)<Integer.valueOf(msg.id)?-1:0); } @Override public long getDelay(TimeUnit unit) { return unit.convert(this.excuteTime - System.nanoTime(), TimeUnit.NANOSECONDS); } public int getId() { return id; } public void setId(int id) { this.id = id; } public IndentCommodity getIndentCommodity() { return indentCommodity; } public void setIndentCommodity(IndentCommodity indentCommodity) { this.indentCommodity = indentCommodity; } }
二;延時執行類
package io.jboot.admin.job; import java.sql.SQLException; import java.util.concurrent.DelayQueue; import com.hnzh.wmall.service.api.CommodityDetailsService; import com.hnzh.wmall.service.api.IndentCommodityService; import com.hnzh.wmall.service.api.IndentService; import com.hnzh.wmall.service.entity.CommodityDetails; import com.hnzh.wmall.service.entity.Indent; import com.hnzh.wmall.service.entity.IndentCommodity; import com.jfinal.log.Log; import com.jfinal.plugin.activerecord.Db; import com.jfinal.plugin.activerecord.IAtom; import io.jboot.Jboot; import io.jboot.admin.base.common.ServiceConst; import io.jboot.core.rpc.Jbootrpc; import io.jboot.core.rpc.JbootrpcServiceConfig; public class ExecuteClass implements Runnable { protected static final Log logger = Log.getLog(ExecuteClass.class); // 延時佇列 private DelayQueue<TaskEntity> queue; public ExecuteClass(DelayQueue<TaskEntity> queue) { this.queue = queue; } @Override public void run() { //獲取rpc服務 Jbootrpc jbootrpc = Jboot.me().getRpc(); JbootrpcServiceConfig serviceConfig = new JbootrpcServiceConfig(); serviceConfig.setGroup(ServiceConst.SERVICE_WMALL); CommodityDetailsService detailsService = jbootrpc.serviceObtain(CommodityDetailsService.class, serviceConfig); IndentService IndentService = jbootrpc.serviceObtain(IndentService.class, serviceConfig); IndentCommodityService indentCommodityService = jbootrpc.serviceObtain(IndentCommodityService.class, serviceConfig); while (true) { try { //檢測該訂單是否已買單 若已買單對該訂單不做處理,進入下次迴圈 IndentCommodity indentCommodity = Jboot.me().getCache().get("DelayExecuteClass", "executeClass"+queue.take().getIndentCommodity().getIndentNumber()); //如果快取中沒取到訂單物件,表示該訂單已支付,或已取消(支付成功時在快取中清除對應訂單) if(indentCommodity == null){ continue; } TaskEntity take = queue.take(); //業務開始 訂單狀態開始執行更新 //更新完畢後從快取中清除該訂單號 Jboot.me().getCache().remove("DelayExecuteClass", "executeClass"+take.getIndentCommodity().getIndentNumber()); logger.debug("訂單號為>>>"+commodity.getIndentNumber() +"的訂單過期狀態更新完畢,cache內已清除"); } catch (InterruptedException e) { e.printStackTrace(); } } } }
三;在定時任務執行類中,將所有需要加入到延時執行佇列中的訂單加入進去。注:定時任務下次更出來吧
// 初始化訂單延時佇列計數器
private static int counter = 0;
/** * 訂單超時定時任務,若超時,則將該訂單資料更新 * * @param minutes * @return */ public synchronized String indentTimeout(String minutes) { //獲取rpc服務 Jbootrpc jbootrpc = Jboot.me().getRpc(); JbootrpcServiceConfig serviceConfig = new JbootrpcServiceConfig(); serviceConfig.setGroup(ServiceConst.SERVICE_WMALL); IndentCommodityService indentCommodityService = jbootrpc.serviceObtain(IndentCommodityService.class, serviceConfig); // 查詢出所有未支付訂單 List<IndentCommodity> commodities = indentCommodityService.findIndentCommodity(null); for (int i = 0; i < commodities.size(); i++) { counter++; // 延時執行時間 轉為毫秒 long time = Integer.parseInt(minutes) * 60 * 1000; long delayTime = time - (new Date().getTime() - commodities.get(i).getCreateTime().getTime()); TaskEntity te = null; if (delayTime < 0) { logger.debug("超過" + minutes + "分鐘未加入到佇列,訂單號>>>" + commodities.get(i).getIndentNumber() + ",立即加入佇列"); te = new TaskEntity(counter, commodities.get(i), 0); } else { te = new TaskEntity(counter, commodities.get(i), delayTime); // 檢測該訂單物件是否在延時佇列中,若存在不做處理 IndentCommodity indentCommodity = Jboot.me().getCache().get("DelayExecuteClass", "executeClass" + commodities.get(i).getIndentNumber()); if (indentCommodity != null) { continue; } } // 將需處理的訂單物件加入到快取內 Jboot.me().getCache().put("DelayExecuteClass", "executeClass" + commodities.get(i).getIndentNumber(), commodities.get(i)); // 將需處理的訂單物件加入到延時佇列中 queue.offer(te); } return "success"; }