订单超时自动取消,延时任务

应用场景,电商项目用户下单后超过指定时间未支付,订单自动失效。

使用延时队列会使用到定时任务,需要先把定时任务做好。

在用户下单成功后。定时任务定时扫描出下单成功且未支付的订单,将订单加入到延时执行队列中。同时也加入到缓存中。

延时执行类在执行订单失效时,先到缓存内查询一次,如果没有查询到,说明该订单已支付或者已取消(支付成功或取消订单清除对应缓存)

一;执行实体

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";
    }

猜你喜欢

转载自blog.csdn.net/weixin_41690497/article/details/82996588