使用redisson实现延迟队列

引入maven

     <dependency>
        <groupId>org.redisson</groupId>
        <artifactId>redisson</artifactId>
        <version>3.13.3</version>
     </dependency>

延迟队列最佳实践

  1. 首先定义一个延迟job,里面包含一个map参数,和队列执行器的具体实现class,触发任务执行时,map参数会被传递到具体的业务执行器实现内
@Data
@NoArgsConstructor
@AllArgsConstructor
public class DelayJob implements Serializable {

    private static final long serialVersionUID = -7558558883792921429L;

    private Map<String,Object> jobParams;//job执行参数
    private String executeTime;//执行时间
    private Class clazz;//具体执行实例实现
}
  1. 定义一个延迟job执行器接口,业务需要实现这个接口,然后在execute方法内写自己的业务逻辑
public interface DelayJobExecutor {
     void execute(DelayJob job);
}
  1. 消费已经到时间的延时job服务,通过job参数调用业务执行器实现
@Component
public class JobTimer {

    static final String jobsTag = "customer_jobtimer_jobs";
    @Autowired
    private RedissonClient client;

    @Autowired
    private ApplicationContext context;

    ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);

    @PostConstruct
    public void startJobTimer() {
        RBlockingQueue blockingQueue = client.getBlockingQueue(jobsTag);
       //下面2行 必不可少 防止出现 服务器重启后,延迟队列take数据阻塞,不执行,必须等到下一个内容offer时,队列才会把阻塞的消息全部处理掉
        RDelayedQueue<DelayJob> delayedQueue = client.getDelayedQueue(blockingQueue);
        delayedQueue.offer(null, 1, TimeUnit.SECONDS);
      
        new Thread(() -> {
            while (true) {
                try {
                    DelayJob job = blockingQueue.take(); //该方法会阻塞,直到能获取到任务
                    log.info("获取到延迟任务:{}, 剩余任务数:{}", job, delayedQueue.size());

                    if (job == null) {
                        continue;
                    }
                    executorService.execute(new ExecutorDelayTask(context, job));
                } catch (Exception e) {
                   log.error("执行延迟任务出现异常,异常原因:{}", e.getMessage(), e);

                    try {
                        TimeUnit.SECONDS.sleep(60);
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                }
            }
        }, "delayJobTimer").start();
      
        log.info("init startDelayJobTimer success");
    }
    class ExecutorTask implements Runnable {

        private ApplicationContext context;

        private DelayJob delayJob;

        public ExecutorTask(ApplicationContext context, DelayJob delayJob) {
            this.context = context;
            this.delayJob = delayJob;
        }

        @Override
        public void run() {
            ExecuteJob service = (ExecuteJob) context.getBean(delayJob.getaClass());
            service.execute(delayJob);
        }
    }
}
  1. 封装延时job服务
@Component
@Slf4j
public class DelayJobService {

    @Resource
    private RedissonClient client;

    /**
     * 提交延迟任务
     *
     * @param job
     * @param delay    延迟的时间
     * @param timeUnit
     */
    public void submitJob(DelayJob job, Long delay, TimeUnit timeUnit) {
        if (delay <= 0) {
            log.error("[submitJob] 延迟时间不能小于0, 任务:{},延迟时间:{}", job, delay);
            return;
        }

        RBlockingQueue<Object> blockingQueue = client.getBlockingQueue(DelayJobTimer.delayJobsTag, JsonJacksonCodec.INSTANCE);
        RDelayedQueue delayedQueue = client.getDelayedQueue(blockingQueue);
        delayedQueue.offer(job, delay, timeUnit);
        log.info("[submitJob] 添加延迟任务成功,job:{}", job);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Redisson 是一个基于 Redis 的 Java 库,它提供了丰富的分布式数据结构和服务,其中包括延迟队列Redisson延迟队列基于 Redis 的有序集合(Sorted Set)实现,通过设置元素的 score 值来实现延迟。元素的 score 值表示元素应该在何时被消费,Redisson 会定期扫描有序集合,找到 score 值小于当前时间的元素进行消费。 下面是一个使用 Redisson 延迟队列的示例代码: ```java // 创建 Redisson 客户端 Config config = new Config(); config.useSingleServer().setAddress("redis://127.0.0.1:6379"); RedissonClient redisson = Redisson.create(config); // 获取延迟队列 RDelayedQueue<String> delayedQueue = redisson.getDelayedQueue(redisson.getQueue("myQueue")); // 添加元素到延迟队列 delayedQueue.offer("hello", 10, TimeUnit.SECONDS); // 10 秒后消费 // 创建消费者线程 new Thread(() -> { RBlockingQueue<String> blockingQueue = redisson.getBlockingQueue("myQueue"); while (!Thread.interrupted()) { try { String item = blockingQueue.take(); System.out.println("consume item: " + item); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }).start(); ``` 上面的示例代码中,首先创建了一个 Redisson 客户端。然后通过 `redisson.getDelayedQueue()` 方法获取了延迟队列对象 `delayedQueue`,并通过 `delayedQueue.offer()` 方法向队列中添加了一个元素,该元素将在 10 秒后被消费。 最后创建了一个消费者线程,通过 `redisson.getBlockingQueue()` 方法获取了阻塞队列对象 `blockingQueue`,并通过 `blockingQueue.take()` 方法从队列中取出元素进行消费。 需要注意的是,上面的示例代码中没有关闭 Redisson 客户端,实际使用中需要在程序退出时调用 `redisson.shutdown()` 方法关闭客户端。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值