@Controller
public class DelayTaskUtil {
private static final ExecutorService pl = Executors.newSingleThreadExecutor();;
private static final DelayQueue<DelayData> queue = new DelayQueue();
private static final int maxQueueNum = 5;
private static String redisKey = "DELAYQUEUE:"+getIp();
private static final String redisSingleKey = "SINGLEKEY";
private static final String redisSingleKeyNeedDel = "SINGLEKEY_NEEDDEL";
private Logger log = LoggerFactory.getLogger(DelayTaskUtil.class);
private static RedisTemplate<String,String> redisTemplate;
@Autowired
@Qualifier("redisTemplate")
private RedisTemplate redisFiledTemplate;
@Autowired
private ApplicationContext applicationContext;
private static IjyscDelayLogDao ijyscDelayLogDao;
@Autowired
private IjyscDelayLogDao logDao;
@Autowired
private Environment environment;
public static Thread thread = null;
public static volatile boolean isSleep = false;
@PostConstruct
public void init(){
redisTemplate = redisFiledTemplate;
ijyscDelayLogDao = logDao;
String port = environment.getProperty("server.port");
redisKey = redisKey +":"+port;
System.out.println(redisKey);
redisFiledTemplate.opsForHash().put(redisSingleKey,redisKey,1);
// execute();
// test();
// redisTemplate.opsForZSet().removeRange(redisKey,0,-1);
}
@PreDestroy
public void destory(){
redisFiledTemplate.opsForHash().put(redisSingleKey,redisKey,0);
}
// @EventListener(classes = {DelayEvent.class})
// public void lister(DelayEvent delayEvent){
// DelayData delayData = delayEvent.getDelayData();
// String id = delayData.getId();
// long time = delayData.getExpire();
// System.out.print("id="+id+" 开始时间:"+time);
// long endtime = System.currentTimeMillis();
// System.out.println(" 结束时间:"+endtime+" 相差:"+(endtime-time));
// }
public void execute(){
pl.execute(new Runnable() {
@Override
public void run() {
thread = Thread.currentThread();
while (true) {
isSleep = false;
JyscDelayLogVO jyscDelayLogVO = new JyscDelayLogVO();
try {
if(queue.isEmpty()){//队列为空
transfeTableToTask();//表中转换到redis
}
transfeTaskToQueue();//redis转换到队列中
if(queue.isEmpty()){
isSleep = true;
LockSupport.parkNanos(60*1000000000L);
isSleep = false;
}else{
DelayData take = queue.take();
jyscDelayLogVO.setExctime(LocalDateTime.now());
jyscDelayLogVO.setMid(take.getId());
jyscDelayLogVO.setResult("2");
updateLog(jyscDelayLogVO);
boolean needDel = removeCurrentDelay(take);//是否已经是作废信息
if(!needDel){
String json = JsonUtil.writeValueAsString(take);
removeDataFromZset(json);
applicationContext.publishEvent(new DelayEvent(this,take));
}
}
} catch (Exception e) {
e.printStackTrace();
String mid = jyscDelayLogVO.getMid();
if(StringUtils.isNotEmpty(mid)){
jyscDelayLogVO.setError(e.getMessage());
jyscDelayLogVO.setErrorDetail(ExceptionUtils.getStackTrace(e));
updateLog(jyscDelayLogVO);
}
}
}
}
});
}
public static void addTask(String id, long expire){
DelayData delayData = new DelayData(id,expire);
addTask(delayData);
}
public static void addTask(DelayData delayData){
String id = delayData.getId();
long expire = delayData.getExpire();
removeTask(id);//取消相同的task
JyscDelayLogVO jyscDelayLogVO = addLog(delayData);
long todayEndTime = getTodayEndTime();
if(expire<todayEndTime){ //当天需要发送的立刻加入redis中
boolean add = true;
List<JyscDelayLogVO> currentExp = ijyscDelayLogDao.getCurrentExp(todayEndTime);
if(CollectionUtils.isNotEmpty(currentExp)){
JyscDelayLogVO log = currentExp.get(0);
String mexp = log.getMexp();
if(StringUtils.isNotEmpty(mexp)){
long todayStartTime = getTodayStartTime();
long dataExp = Long.parseLong(mexp);
if((expire>dataExp&&dataExp>=todayStartTime)){
add = false;
}
}
}
if(add){
addToZSet(delayData,expire);
//更新
JyscDelayLogVO update = new JyscDelayLogVO();
update.setRediskey(redisKey);
update.setId(jyscDelayLogVO.getId());
update.setUpdateDatetime(LocalDateTime.now());
ijyscDelayLogDao.updDelayRedisKey(update);
transfeTaskToQueue();//redis转换到队列中
}
if(thread!=null&&isSleep){
LockSupport.unpark(thread);
}
}
}
/**
* 获取当天最后时间
* @return 返回时间戳
*/
public static long getTodayEndTime(){
ZoneId zone = ZoneId.systemDefault();
Instant instant = LocalDate.now().atTime(23, 59, 59).atZone(zone).toInstant();
return instant.toEpochMilli();
}
public static long getTodayStartTime(){
ZoneId zone = ZoneId.systemDefault();
Instant instant = LocalDate.now().atTime(0, 0, 1).atZone(zone).toInstant();
return instant.toEpochMilli();
}
/**
* 返回秒数
* @param time 指定时间
* @param seconds 延迟时间
* @return 返回时间戳
*/
public static long getMilli(LocalDateTime time,long seconds){
ZoneId zone = ZoneId.systemDefault();
Instant instant = time.plusSeconds(seconds).atZone(zone).toInstant();
return instant.toEpochMilli();
}
public static void transfeTableToTask(){
cleanRedisSingleKeyNeedDel();//清理需要删除的队列信息
JyscDelayLogVO jyscDelayLogVO = new JyscDelayLogVO();
jyscDelayLogVO.setResult("1");
jyscDelayLogVO.setMexp(Long.toString(getTodayEndTime()));
List<JyscDelayLogVO> logs = ijyscDelayLogDao.getLog(jyscDelayLogVO);
if(CollectionUtils.isNotEmpty(logs)){
JyscDelayLogVO update = new JyscDelayLogVO();
LocalDateTime now = LocalDateTime.now();
for (JyscDelayLogVO log : logs) {
Integer version = log.getVersion();
update.setVersion(version);
update.setNewVersion(version+1);
update.setRediskey(redisKey);
update.setMid(log.getMid());
update.setResult("1");
update.setUpdateDatetime(now);
int i = ijyscDelayLogDao.updDelayLog(update);
if(i>0){
String message = log.getMessage();
String mexp = log.getMexp();
addToZSet(message,Long.parseLong(mexp));
}
}
}
}
/**
* 增加日志
* @param delayData
*/
public static JyscDelayLogVO addLog(DelayData delayData){
JyscDelayLogVO jyscDelayLogVO = new JyscDelayLogVO();
jyscDelayLogVO.setMid(delayData.getId());
long expire = delayData.getExpire();
jyscDelayLogVO.setMexp(Long.toString(expire));
jyscDelayLogVO.setMessage(JsonUtil.writeValueAsString(delayData));
jyscDelayLogVO.setCreateDatetime(LocalDateTime.now());
jyscDelayLogVO.setResult("1");
jyscDelayLogVO.setName(getName(delayData.getId()));
jyscDelayLogVO.setDisabled(0);
ijyscDelayLogDao.addDelayLog(jyscDelayLogVO);
return jyscDelayLogVO;
}
/**
* 更新日志
* @param jyscDelayLogVO
*/
public static void updateLog(JyscDelayLogVO jyscDelayLogVO){
jyscDelayLogVO.setUpdateDatetime(LocalDateTime.now());
ijyscDelayLogDao.updDelayLog(jyscDelayLogVO);
}
public static String getName(String mid){
for (DelayEnum value : DelayEnum.values()) {
String val = value.getValue();
if(mid.startsWith(val)){
return value.getName();
}
}
return "";
}
/**
* 删除信息,跨微服务删除zset和队列中的作废信息
* @param id
*/
public static void removeTask(String id){
if(StringUtils.isEmpty(id)){
throw new BusinException("600","必须有ID");
}
JyscDelayLogVO jyscDelayLogVO = new JyscDelayLogVO();
jyscDelayLogVO.setMid(id);
List<JyscDelayLogVO> logs = ijyscDelayLogDao.getLogByMid(jyscDelayLogVO);
if(CollectionUtils.isNotEmpty(logs)){
LocalDateTime now = LocalDateTime.now();
for (JyscDelayLogVO log : logs) {
String key = log.getRediskey();
String result = log.getResult();
String message = log.getMessage();
if("1".equals(result)&&StringUtils.isNotEmpty(key)){
if(redisKey.equals(key)){
DelayData delayData = new DelayData(id,0l);
queue.remove(delayData);//删除成功
redisTemplate.opsForZSet().remove(key,message);
}else{
redisTemplate.opsForZSet().remove(key,message);
redisTemplate.opsForHash().put(redisSingleKeyNeedDel,id,key);//保存需要删除的消息
}
}
log.setDisabled(1);
log.setUpdateDatetime(now);
ijyscDelayLogDao.delDelayLog(log);
}
}
}
/**
* 删除当前微任务的队列垃圾信息
* @param delayData
*/
public boolean removeCurrentDelay(DelayData delayData){
Boolean exist = redisTemplate.opsForHash().hasKey(redisSingleKeyNeedDel, delayData.getId());
if(exist){
Object value = redisTemplate.opsForHash().get(redisSingleKeyNeedDel, delayData.getId());
if(redisKey.equals(String.valueOf(value))){
redisTemplate.opsForHash().delete(redisSingleKeyNeedDel,delayData.getId());
return true;
}
}
return false;
}
/**
*
* @param key
* @param id
* @return 0 redis空 ,1找到可能在队列中, 2找到不在队列中,-1未找到
*/
private static int removeRedisZSet(String key,String id){
Long size = redisTemplate.opsForZSet().size(key);
long head = size>maxQueueNum?maxQueueNum:size;
long tail = size - maxQueueNum;
if(size==0){
return 0; //redis的zset为空
}
if(size>0){
Set<String> range = redisTemplate.opsForZSet().range(key, 0, head);
for (String s : range) {
if(s.contains(id)){
redisTemplate.opsForZSet().remove(key,s);
return 1;//前五
}
}
if(tail>0){
Set<String> other = redisTemplate.opsForZSet().range(key, head, -1);
for (String s : other) {
if(s.contains(id)){
redisTemplate.opsForZSet().remove(key,s);
return 2;//只在redis中
}
}
}
}
return -1;//未找到
}
@RequestMapping("/test")
public void test(@RequestParam Integer s) {
long time =System.currentTimeMillis()+s*1000;
String id = "1"+s;
addTask(id,time);
}
public static void transfeTaskToQueue(){
cleanRedisSingleKeyNeedDel();//清理需要删除的队列信息
Set<String> dataFromZset = getDataFromZset(maxQueueNum);
if(dataFromZset!=null){
for (String str : dataFromZset) {
DelayData delayData = JsonUtil.readValue(str,DelayData.class);
addQueue(delayData);//添加任务队列
}
}
//清理队列
int num = queue.size() - maxQueueNum;
if(num > 0){
Iterator<DelayData> iterator = queue.iterator();
DelayData maxDelay = null;
for(int i=num;i>0;i--){
while(iterator.hasNext()){
DelayData next = iterator.next();
if(maxDelay==null||maxDelay.getExpire()<next.getExpire()){
maxDelay = next;
}
}
queue.remove(maxDelay);
}
}
}
/**
* 清理需要删除的队列信息
*/
public static void cleanRedisSingleKeyNeedDel(){
Map<Object, Object> entries = redisTemplate.opsForHash().entries(redisSingleKeyNeedDel);
if(entries!=null && entries.size()>0){
for (Map.Entry<Object, Object> objectObjectEntry : entries.entrySet()) {
String value = String.valueOf(objectObjectEntry.getValue());
if(redisKey.equals(value)){
String key = String.valueOf(objectObjectEntry.getKey());
DelayData delayData = new DelayData(key,0l);
queue.remove(delayData);
redisTemplate.opsForHash().delete(redisSingleKeyNeedDel,key);
}
}
}
}
/**
* 添加任务队列
* @param delayData
*/
public static void addQueue(DelayData delayData){
if(queue.contains(delayData)){
queue.remove(delayData);
}
queue.put(delayData);
}
/**
* 添加zset
* @param value
* @param score
*/
public static void addToZSet(DelayData value, long score) {
String str = JsonUtil.writeValueAsString(value);
addToZSet(str,score);
}
public static void addToZSet(String str, long score) {
redisTemplate.opsForZSet().add(redisKey, str, score);
}
/**
* 获取数据
* @param num >=1
* @return
*/
public static Set<String> getDataFromZset(long num){
long l = redisTemplate.opsForZSet().size(redisKey).longValue();
if(l==0){
return null;
}
return redisTemplate.opsForZSet().range(redisKey, 0, num-1);
}
/**
* 删除数据
* @param delayData
*/
public static void removeDataFromZset(String delayData){
redisTemplate.opsForZSet().remove(redisKey,delayData);
}
public static String getIp(){
//得到IP,
InetAddress ia = null;
try {
ia = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
e.printStackTrace();
}
String ip=ia.toString().split("/")[1];
// ip = ip.replaceAll("\\.","_");
System.out.println(ia);
System.out.println("本机的IP:"+ip);
//得到IP,输出PC-201309011313/122.206.73.83
return ip;
}
}