实现如下:
1、添加maven依赖
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.13.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
2、定义redisson生产、消费操作类
package com.lf.delay;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Slf4j
@Component
public class DelayService {
private final RedissonClient redissonClient;
public DelayService(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
}
/**
* 向阻塞队列生产数据
* @param delayQueue 队列名称
* @param t 数据类型
* @param delay 延时时间
* @param timeUnit 时间单位
* @param <T> 类型
*/
public <T> void produce(String delayQueue, T t, long delay, TimeUnit timeUnit) {
try {
log.info("delay msg,delayQueue:{},key:{},delay:{}", delayQueue, t, delay);
if (delay < 0) {
delay = 0;
}
RBlockingQueue<T> blockingFairQueue = redissonClient.getBlockingQueue(delayQueue);
RDelayedQueue<T> delayedQueue = redissonClient.getDelayedQueue(blockingFairQueue);
delayedQueue.offer(t, delay, timeUnit);
}catch (Exception e){
log.error("添加延时任务队列失败",e);
}
}
/**
* 获取阻塞队列数据
* @param queueName 队列名称
* @param <T> 返回类型
* @return value
* @throws InterruptedException 异常中断
*/
public <T> T take(String queueName) throws InterruptedException {
RBlockingQueue<T> blockingQueue = redissonClient.getBlockingQueue(queueName);
return blockingQueue.take();
}
}
3、定义消费者基础操作类
package com.lf.delay;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RedissonClient;
import java.util.function.Consumer;
/**
* 延时队列消费者
*/
@Slf4j
public class DelayTaskConsumer<T> {
private final String delayQueue;
private final Consumer<T> consumer;
private final RedissonClient redissonClient;
public DelayTaskConsumer(String delayQueue,
RedissonClient redissonClient,
Consumer<T> consumer) {
this.delayQueue = delayQueue;
this.consumer = consumer;
this.redissonClient = redissonClient;
new Thread(new DelayTaskHandler()).start();
}
public class DelayTaskHandler implements Runnable {
@Override
public void run() {
log.info("准备启动消费线程 queue={}",delayQueue);
RBlockingQueue<T> blockingFairQueue = redissonClient.getBlockingQueue(delayQueue);
//订阅redis队列
log.info("开始订阅延时队列 queue={}",delayQueue);
redissonClient.getDelayedQueue(blockingFairQueue);
log.info("订阅延时队列成功 queue={}",delayQueue);
while (true) {
try {
log.info("开始获取延时消息 queue={}",delayQueue);
T value = blockingFairQueue.take();
log.info("delay queue {},延时任务开始执行,value - {} , timeStamp - {} , threadName - {}", delayQueue, value, System.currentTimeMillis(), Thread.currentThread().getName());
consumer.accept(value);
log.info("延时消息提交任务成功 queue={}",delayQueue);
} catch (Exception e) {
// log.error("延时任务执行失败,", e);
}
}
}
}
}
4、对应的业务消费这实现类
队列常量类
package com.lf.delay;
public interface DelayConfig {
String APP_ID = "lf-redisson-test";
String UAL_UP_DELAY_KEY = APP_ID + ":" + "ual_up_delay_queue";
String UAL_LOWER_DELAY_KEY = APP_ID + ":" + "ual_lower_delay_queue";
}
package com.lf.delay;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.Date;
/**
* 定时上下架任务
*/
@Component
@Slf4j
public class DelayUalTask implements InitializingBean {
private final RedissonClient redissonClient;
public DelayUalTask(RedissonClient redissonClient){
this.redissonClient = redissonClient;
}
@Override
public void afterPropertiesSet() {
log.info("直播定时上下架任务开始,time:{}", new Date());
new DelayTaskConsumer<>(DelayConfig.UAL_UP_DELAY_KEY, redissonClient, this::delayUp);
new DelayTaskConsumer<>(DelayConfig.UAL_LOWER_DELAY_KEY, redissonClient, this::delayLower);
}
/**
* 延时下架
*/
private void delayLower(String key) {
log.info("延时下架,liveId:{}", key);
// 下架
}
/**
* 延时上架
*/
private void delayUp(String key) {
log.info("延时上架,liveId:{}", key);
}
}
5、业务test
@RunWith(SpringRunner.class)
@SpringBootTest
public class DelayUalTest {
@Autowired
DelayService delayService;
@Test
public void delayUal() {
Date left = new Date();
Date right = new Date();
Pair<Date, Date> syncUal = Pair.of(left, right);
String key = "businessCode"+"key";
try {
if (Objects.nonNull(syncUal.getLeft())) {
delayService.produce(DelayConfig.UAL_UP_DELAY_KEY, key, syncUal.getLeft().getTime() - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}
if (Objects.nonNull(syncUal.getRight())) {
delayService.produce(DelayConfig.UAL_LOWER_DELAY_KEY, key, syncUal.getRight().getTime() - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}
} catch (Exception e) {
}
}
}
原理参考文章如下:
https://www.jianshu.com/p/977466020144/
redisson延迟队列的实现参考:
https://www.cnblogs.com/better-farther-world2099/articles/15216447.html