引入maven
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.13.3</version>
</dependency>
延迟队列最佳实践
- 首先定义一个延迟job,里面包含一个map参数,和队列执行器的具体实现class,触发任务执行时,map参数会被传递到具体的业务执行器实现内
@Data
@NoArgsConstructor
@AllArgsConstructor
public class DelayJob implements Serializable {
private static final long serialVersionUID = -7558558883792921429L;
private Map<String,Object> jobParams;
private String executeTime;
private Class clazz;
}
- 定义一个延迟job执行器接口,业务需要实现这个接口,然后在execute方法内写自己的业务逻辑
public interface DelayJobExecutor {
void execute(DelayJob job);
}
- 消费已经到时间的延时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);
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);
}
}
}
- 封装延时job服务
@Component
@Slf4j
public class DelayJobService {
@Resource
private RedissonClient client;
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);
}
}