使用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);
    }
}

猜你喜欢

转载自blog.csdn.net/kaihuishang666/article/details/108467075