DelayTaskUtil
@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; } }