一、定义延迟任务类
java
package com.activity.domain;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
/**
* 延迟任务类
*/
public class DelayedCancellation implements Delayed {
private String order;
private final long delayTime; // 延迟时间
public DelayedCancellation(String order, long delayTime) {
this.order = order;
this.delayTime = System.currentTimeMillis() + delayTime;
}
public String getOrder() {
return order;
}
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(delayTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}
@Override
public int compareTo(Delayed o) {
return Long.compare(this.delayTime, ((DelayedCancellation) o).delayTime);
}
}
二、执行任务
java
package com.activity.utils;
import java.util.concurrent.DelayQueue;
import com.zaiyun.activity.domain.DelayedCancellation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CancellationManager {
private static final Logger wechatLogger = LoggerFactory.getLogger("extend-wechat");
private final DelayQueue<DelayedCancellation> delayQueue = new DelayQueue<>();
public void scheduleOrderCancellation(String order, long delayTime) {
DelayedCancellation delayedOrderCancellation = new DelayedCancellation(order, delayTime);
delayQueue.put(delayedOrderCancellation);
}
public void startOrderCancellationScheduler() {
new Thread(() -> {
while (true) {
try {
DelayedCancellation delayedOrderCancellation = delayQueue.take();
processOrderCancellation(delayedOrderCancellation.getOrder());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}).start();
}
/**
* 执行取消操作
* @param order
*/
private void processOrderCancellation(String order) {
wechatLogger.info("执行取消任务-订单编号:" + order);
}
}
三、触发使用
java
/**
* 30分钟未支付将取消参与
*/
public static void cancelParticipation(String order) {
CancellationManager cancellationManager = new CancellationManager();
cancellationManager.startOrderCancellationScheduler();
cancellationManager.scheduleOrderCancellation(order, TimeUnit.MINUTES.toMillis(30));
wechatLogger.info("触发延时队列-订单编号:" + order);
}
四、执行日志
五、服务重启问题
在调试的过程中发现一个严重的问题 (重启服务后任务丢失了 )
因为延迟队列没有做持久化,那么服务重启之后,原来在队列的任务就丢失啦。所以,服务重启的时候要去扫描检测订单。
ApplicationRunner执行时机为容器启动完成的时候,实现run方法即可。或使用InitializingBean接口。
java
package com.activity.domain;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
/**
* 初始化执行任务
*/
@Component
public class InitializeTask implements ApplicationRunner {
private static final Logger wechatLogger = LoggerFactory.getLogger("extend-wechat");
@Override
public void run(ApplicationArguments args) {
wechatLogger.info("初始化执行任务:");
}
}
本文参考 使用延迟队列处理超时订单