使用redis和线程池实现需求截止时间到期处理

使用redis和线程池实现需求截止时间到期处理



业务需求

使用redis和线程池实现延迟到期订单。
业务:新增需求,设置截止日期,根据截止日期改变该需求的状态为已截止
实现步骤:

  1. 在新增需求接口中发送延迟消息(延迟时间为:截止时间和当前时间的时间差+当前时间) 以set类型存储(已截图展示)number为该需求的code编码。
  2. 实现CommandLineRunner方法,在程序启动时执行run方法。在run方法中另开线程,阻塞获取消息(如果没有获取到截止的消息则循环每秒检查一次,直到获取到消息),每次只获取一条消息,如果获取到了,则返回该需求的编码。
  3. 如果编码存在,则调用redisDelayQueueHandle.execute(code)方法,在该方法中改变该需求的状态为已截止

    在这里插入图片描述

一、实现步骤

1.引入库

 <dependency>
                <groupId>org.redisson</groupId>
                <artifactId>redisson-spring-boot-starter</artifactId>
                <version>3.18.0</version>
            </dependency>

2.发生延时消息

  @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(DemandDTO demandDTO) {
        //TODO 需求插入的实现,获取需求的code,和截止时间
        // 发送延迟消息
        long seconds = LocalDateTimeUtil.between(LocalDateTime.now(), demandDTO.getCloseTime(), ChronoUnit.SECONDS);
        redisDelayedQueue.addMessage("supplyDemandExpire", demandDTO.getCode(), seconds);
    }

3.基于redis的zset实现延迟队列RedisDelayedQueue

/**
 * @description 基于redis的zset实现延迟队列
 */
@Component
public class RedisDelayedQueue {


    @Resource
    private StringRedisTemplate stringRedisTemplate;


    // 添加消息到延迟队列
    public void addMessage(String queueName, String message, long delaySeconds) {
        long score = System.currentTimeMillis() / 1000 + delaySeconds;
        stringRedisTemplate.opsForZSet().add(queueName, message, score);
    }

    // 获取并移除已到期的消息
    public String pollMessage(String queueName) {
        long now = System.currentTimeMillis() / 1000;
        //每次获取一条消息
        Set<String> messages = stringRedisTemplate.opsForZSet().rangeByScore(queueName, 0, now, 0, 1);

        if (CollUtil.isEmpty(messages)) {
            return null;
        }
        String message = messages.iterator().next();
        stringRedisTemplate.opsForZSet().remove(queueName, message);
        return message;
    }

    // 移除消息
    public void removeMessage(String queueName, String message) {
        stringRedisTemplate.opsForZSet().remove(queueName, message);
    }

    // 阻塞获取消息
    public String takeMessage(String queueName) throws InterruptedException {
        String message;
        //若一直没有获取到消息,则一直阻塞循环检查
        while ((message = pollMessage(queueName)) == null) {
            TimeUnit.SECONDS.sleep(1); // 每秒检查一次
        }
        return message;
    }
}

4.实现CommandLineRunner方法

在程序启动时执行run方法


/**
 * @description 启动延迟队列
 */
@Slf4j
@Component
public class RedisDelayQueueRunner implements CommandLineRunner {

    @Autowired
    private RedisDelayedQueue redisDelayedQueue;

    @Autowired
    private RedisDelayQueueHandle<String> redisDelayQueueHandle;
    
    @Override
    public void run(String... args) throws Exception {
        ThreadPoolUtils.execute(() -> {
            while (true) {
                try {
                    //获取消息(code)
                    String value = redisDelayedQueue.takeMessage("supplyDemandExpire");
                    if (StrUtil.isNotBlank(value)) {
                        log.info("【检测队列中存在过期value】,value:{}", value);
                        //执行需求状态变更(变为已截止状态)
                        redisDelayQueueHandle.execute(value);
                    }
                } catch (Exception e) {
                    log.error("【消费延迟队列消息失败】", e);
                }
            }

        });

    }

5.redis延迟队列执行器:RedisDelayQueueHandle

/**
 * @description redis延迟队列执行器
 */
public interface RedisDelayQueueHandle<T> {

    void execute(T t);

}

6.需求发布已过期过期处理:DemandQueueHandle


/**
 * @description 需求发布已过期过期处理
 */
@Component
public class DemandQueueHandle implements RedisDelayQueueHandle<String> {

    @Resource
    private DemandService demandService;

    @Override
    public void execute(String demandCode) {
        if (StrUtil.isNotBlank(demandCode)) {
            Demand demand = demandService.lambdaQuery().eq(SupplyDemand::getCode, demandCode).one();
            if (demand != null) {
                demandService.updateDemandStatus(demand.getCode(),"已截止");
            }
        }

    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值