Delayed延时队列 来实现关闭已超时的任务或订单

1、定义延时订单类

定义唯一的订单编号、活动ID、超时时间、类型等你业务可能需要用到的字段
类需要实现Delayed, Serializable 接口

@Data
public class TaskDelayedVo implements Delayed, Serializable {

    /**
     * 任务id
     */
    private String orderNo;

    /**
     * 活动id
     */
    private Long activityId;

    /**
     * 任务状态
     */
    private String taskStates;

    /**
     * 订单过期时间(毫秒)
     */
    private long expTime;

    @Override
    public long getDelay(TimeUnit unit) {
        return unit.convert(this.expTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
    }

    @Override
    public int compareTo(Delayed o) {
        // return Long.valueOf(this.expTime).compareTo(Long.valueOf(((OrderDelayedVo) o).expTime));
        return Long.compare(this.expTime, ((TaskDelayedVo) o).expTime);
    }

    /**
     * 重写用于删除
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        TaskDelayedVo order = (TaskDelayedVo) obj;
        if (order.getOrderNo() == null) {
            return false;
        } else return orderNo.equals(order.getOrderNo());
    }

}

2、处理超时订单实现类

@Slf4j
@Service("taskDelayService")
public class TaskDelayService implements InitializingBean {

    @Resource
    private PrPraiseTaskService prPraiseTaskService;

    private static final DelayQueue<TaskDelayedVo> delayQueue = new DelayQueue<>();
    private static final AtomicBoolean start = new AtomicBoolean(false);
    // 线程池
    private static final ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("taskDelay-pool-%d").build();
    private static final ExecutorService executorService = new ThreadPoolExecutor(
            3, // 核心线程池大小
            6, // 最大线程池大小
            60L, // 线程最大空闲时间
            TimeUnit.MILLISECONDS, // 时间单位(毫秒)
            new LinkedBlockingQueue<>(),  // 线程等待队列
            threadFactory, // 线程创建工厂
            new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
    );

    @Override
    public void afterPropertiesSet() throws Exception {
        start();
    }

    public <T> void start() {
        if (start.get()) {
            return;
        }
        start.set(true);
        // 处理已超时任务
        List<PrPraiseTask> dealList = prPraiseTaskService.dealOverTimeTask();
        if (!CollectionUtils.isEmpty(dealList)) {
            for (PrPraiseTask prPraiseTask : dealList) {
                // 设置任务超时
                boolean result = prPraiseTaskService.setTaskOverTime(prPraiseTask.getId(),prPraiseTask.getActivityId());
                log.info("关闭店铺{}超时订单====>> 订单号:{},是否调用成功:{}",prPraiseTask.getShopName(), prPraiseTask.getOrderNo(),result);

            }
            log.info("已处理超时订单共{}条", dealList.size());
        }

        // 查询未超时订单 放入队列
        List<PrPraiseTask> taskList = prPraiseTaskService.getNotOverTimeTask();
        if (!CollectionUtils.isEmpty(taskList)) {
            List<TaskDelayedVo> list = new ArrayList<>();
            for (PrPraiseTask prPraiseTask : taskList) {
                TaskDelayedVo vo = new TaskDelayedVo();
                vo.setOrderNo(prPraiseTask.getOrderNo());
                vo.setTaskStates(prPraiseTask.getTaskStates());// drawOrder
                vo.setExpTime(prPraiseTask.getCreateTime().getTime() + (30 * 60 * 1000));// 超时时间:30分钟后
                // vo.setExpTime(prPraiseTask.getCreateTime().getTime() + (5 * 1000));// 超时时间:5秒
                list.add(vo);
            }
            log.info("加入超时订单队列,共{}条。", list.size());
            delayQueue.addAll(list);
        }
        executorService.submit(() -> {
            // 取消订单
            while (start.get()) {
                try {
                    TaskDelayedVo order = delayQueue.take();
                    boolean flag = false;
                    // 处理订单过期
                    if (order.getTaskStates().equals("drawOrder")){// 领取任务状态
                    //业务逻辑
                        flag = prPraiseTaskService.setTaskOverTime(valueOf(order.getOrderNo()),order.getActivityId());
                    } else if (order.getTaskStates().equals("verifyOrder")){// 凭证审核通过
                    		// 业务逻辑
                    			........
                    }
                    if (flag) {
                        log.info("超时订单延时队列====>>>  【通知{}关闭超时订单】====>> 订单号:{},是否成功调用:{}", order.getOrderNo(),order.getOrderNo(), flag);
                    } else {
                        log.info("超时订单延时队列====>>>   订单号为[{}],是否执行了关闭操作:{}。", order.getOrderNo(), flag);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    log.info("超时订单延时队列====>>>  处理队列出现异常.");
                }
            }
        });
    }

    public void add(TaskDelayedVo order) {
        if (!start.get()) {
            throw new DollycatException(DollyResultCode.ORDER_SERVER_NOT_START);
        }
        log.info("加入超时订单队列,订单号:{}", order.getOrderNo());
        delayQueue.add(order);
    }

    public boolean delete(String orderNo) {
        if (!start.get()) {
            throw new DollycatException(DollyResultCode.ORDER_SERVER_NOT_START);
        }
        log.info("移除超时订单队列,订单号:{}", orderNo);
        return delayQueue.remove(orderNo);
    }

    public int getSize() {
        if (!start.get()) {
            throw new DollycatException(DollyResultCode.ORDER_SERVER_NOT_START);
        }
        return delayQueue.size();
    }
}

这里就是处理超时后的逻辑,对应上面代码领取任务状态过去的处理逻辑。

@Service("prPraiseTaskService")
public class PrPraiseTaskServiceImpl implements PrPraiseTaskService {

	@Resource
    private PrTempRemainDailyCountDao prTempRemainDailyCountDao;
    
    @Resource
    private PrPraiseTaskDao prPraiseTaskDao;
 	/**
     * 根据任务id设置任务超时
     * @param id 任务id
     * @param activityId 活动id
     * @return boolean
     */
    @Override
    public boolean setTaskOverTime(Long id,Long activityId) {
        PrPraiseTask prPraiseTask = prPraiseTaskDao.queryById(id);
        boolean flag = prPraiseTaskDao.setTaskOverTimeById(id) > 0;
        if (flag) {
            // 任务创建日期(yyyy-MM-dd)
            Date taskCreateTime = DateUtil.parse(DateUtil.format(prPraiseTask.getCreateTime(), DateUtils.ISO_DATE_FORMAT));
            // 当前日期(yyyy-MM-dd)
            Date nowDate = DateUtil.parse(DateUtil.format(DateUtil.parse(DateUtil.now()), DateUtils.ISO_DATE_FORMAT));
            // 任务的创建时间必须等于当天任务释放才回赠一个活动数量
            AssertUtils.isTrue(0 == DateUtil.compare(taskCreateTime, nowDate),
                    prPraiseTask,
                    cus ->  prTempRemainDailyCountDao.releaseCountBack(activityId));
        }
        return flag;
    }
}

3、在创建订单或任务的方法中加入延时队列

@Service("prPraiseTaskService")
public class PrPraiseTaskServiceImpl implements PrPraiseTaskService {
	
	@Resource
    private TaskDelayService taskDelayService;

	@Override
    @Transactional(rollbackFor = Exception.class)
    public boolean receiveTaskByNumberId(Long id) {
        		// 业务逻辑
        		.........
        		
                // 延时队列
                TaskDelayedVo taskDelayedVo = new TaskDelayedVo();
                taskDelayedVo.setOrderNo(prPraiseTask.getId().toString());// 刚创建任务的id
                taskDelayedVo.setActivityId(prPraiseTask.getActivityId());// 该活动的id,用于释放时去回增余量
                taskDelayedVo.setTaskStates(prPraiseTask.getTaskStates());// 默认状态 drawOrder
                // taskDelayedVo.setExpTime(prPraiseTask.getCreateTime().getTime() + (30 * 60 * 1000));// 创建时间
                taskDelayedVo.setExpTime(prPraiseTask.getCreateTime().getTime() + (5 * 1000));// 创建时间,这里为了方便测试我就只设置了5秒
                taskDelayService.add(taskDelayedVo);
}                

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值