Jeecg通过Redission定时发送通知

业务简介

订单创建时会填写一个预期时间,完成时间大于预期时间则需要发送系统通知给管理员

实现方式

  • 定时任务轮询
  • Redission
  • 消息中间件

因为订单不会太多,轮询太过频繁会占用大量资源,故选择了通过Redission的方式来定时发送

AI代码

通过AI生成了代码,并调试验证,现粘贴备份

topic常量
public interface DelayQueueTopic {

  String TICKET_TIMEOUT = "ticket_timeout_queue";
}
队列处理器
public interface RedisDelayQueueHandler<T> {

  /**
   * 队列名称
   */
  String getQueueName();

  /**
   * 队列中到期后的处理逻辑
   */
  void execute(T data);
}
队列工具类
@Component
@Slf4j
public class RedisDelayQueueUtil {

  @Autowired
  private RedissonClient redissonClient;

  public void addDelayTask(String queueName, Long ticketId, long delay, TimeUnit unit) {
    RDelayedQueue<String> delayed = getDelayedQueue(queueName);
    delayed.offer(ticketId.toString(), delay, unit);
    log.info("[DelayQueue] 添加任务 queue={} data={} delay={}", queueName, ticketId, delay);
  }


  public <T> RBlockingQueue<T> getBlockingQueue(String queueName) {
    return redissonClient.getBlockingQueue(queueName);
  }

  public <T> RDelayedQueue<T> getDelayedQueue(String queueName) {
    RBlockingQueue<T> queue = getBlockingQueue(queueName);
    return redissonClient.getDelayedQueue(queue);
  }

  /**
   * 删除延迟任务(取消订单等场景)
   */
  public boolean removeDelayed(String queueName, Long ticketId) {
    log.info("[DelayQueue] 删除任务 queue={} data={}", queueName, ticketId);
    RDelayedQueue<String> delayedQueue = getDelayedQueue(queueName);
    boolean result = delayedQueue.remove(ticketId.toString());
    log.info("[DelayQueue] 删除结果 queue={} data={} result={}", queueName, ticketId, result);
    return result;
  }
}
消费者
@Component
@Slf4j
public class RedisDelayQueueConsumer {

  @Autowired
  private RedisDelayQueueUtil redisDelayQueueUtil;

  @Autowired
  private List<RedisDelayQueueHandler<?>> handlers;

  @EventListener(ApplicationReadyEvent.class)
  public void start() {
    log.info("[DelayQueue] 初始化 {} 个队列监听器", handlers.size());

    for (RedisDelayQueueHandler handler : handlers) {

      String queueName = handler.getQueueName();

      new Thread(() -> {
        log.info("[DelayQueue] 队列 {} 开始监听", queueName);

        RBlockingQueue<Object> queue = redisDelayQueueUtil.getBlockingQueue(queueName);

        while (true) {
          try {
            Object data = queue.take();
            handler.execute(data);
          } catch (Exception e) {
            log.error("[DelayQueue] 队列 {} 异常", queueName, e);
          }
        }
      }, "delay-thread-" + queueName).start();
    }
  }
}
订单超时处理器
@Component
@Slf4j
public class TicketTimeoutHandler implements RedisDelayQueueHandler<String> {
  @Override
  public String getQueueName() {
    return DelayQueueTopic.TICKET_TIMEOUT;
  }

  @Override
  public void execute(String ticketId) {
    log.info("运输工单超时通知:{}", ticketId);
    // todo 发送通知
  }
}
调用代码
	//添加队列任务
	redisDelayQueueUtil.addDelayTask(DelayQueueTopic.TICKET_TIMEOUT, 1234,180, TimeUnit.SECONDS);
	//移除任务
    redisDelayQueueUtil.removeDelayed(DelayQueueTopic.TICKET_TIMEOUT, 1234);

注意事项

超时时间过短

1.可能会导致对象还未创建,消费者处理任务时目标对象数据为空
2.移除对象时对象已经被移入消费者队列,无法移除

移除对象失败

1.超时时间设置过短,比如100ms、1s等
2.传参使用了long这个类型,可能会被redis序列化处理成Integer,导致key对不上删除失败

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值