1. 简介
1.1 什么是延迟任务?
-
定时任务:有固定周期的,有明确的触发时间
-
延迟队列:没有固定的开始时间,它常常是由一个事件触发的,而在这个事件触发之后的一段时间内触发另一个事件,任务可以立即执行,也可以延迟
1.2 应用场景
- 场景一:订单下单之后30分钟后,如果用户没有付钱,则系统自动取消订单;如果期间下单成功,任务取消
- 场景二:接口对接出现网络问题,1分钟后重试,如果失败,2分钟重试,直到出现阈值终止
1.3 redis实现延迟方式
-
Redis中的zset数据类型的去重有序(分数排序)特点进行延迟。
-
例如使用时间戳作为score进行排序
2. 实现步骤
- 首先需要添加Redis的依赖,在pom.xml文件中添加以下内容:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- 创建Redis配置类,配置Redis连接信息:
@Configuration
public class RedisConfig {
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(new RedisStandaloneConfiguration("localhost", 6379));
}
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory());
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new GenericToStringSerializer<>(Object.class));
return template;
}
}
- 创建延迟队列处理类,实现将消息存储到Redis中的延迟队列中:
@Component
public class DelayQueueHandler {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
//添加消息,并指定延迟时间
public void push(String key, Object value, long delayTime) {
redisTemplate.opsForZSet().add(key, value, System.currentTimeMillis() + delayTime);
}
//删除消息
public void remove(String key, Object value) {
redisTemplate.opsForZSet().remove(key, value);
}
//
public List<Object> pop(String key, long startTime, long endTime) {
Set<Object> values = redisTemplate.opsForZSet().rangeByScore(key, startTime, endTime);
List<Object> result = new ArrayList<>(values);
redisTemplate.opsForZSet().removeRangeByScore(key, startTime, endTime);
return result;
}
}
- 在需要使用延迟队列的地方,实现向延迟队列中添加延迟消息:
@Autowired
private DelayQueueHandler delayQueueHandler;
public void addToDelayQueue() {
long delayTime = 10000; // 延迟10秒
String key = "delay_queue:test";
Object value = "test_message";
delayQueueHandler.push(key, value, delayTime);
}
- 定时任务类,实现定时从Redis延迟队列中获取消息,并进行下一步处理:
@Component
public class DelayQueueTask {
@Autowired
private DelayQueueHandler delayQueueHandler;
@Scheduled(fixedDelay = 1000)
public void execute() {
String key = "delay_queue:test";
long startTime = 0;
long endTime = System.currentTimeMillis();
List<Object> values = delayQueueHandler.pop(key, startTime, endTime);
for (Object value : values) {
// 处理延迟消息
}
}
}
-
开启springboot的延迟任务
在spring boot的启动类上面添加注解**@EnableScheduling**
这样就实现了Spring Boot中使用Redis实现延迟队列的功能。