|  |  | @ -2,13 +2,17 @@ package com.epmet.controller; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | import com.epmet.commons.extappauth.annotation.ExternalAppRequestAuth; | 
			
		
	
		
			
				
					|  |  |  | import com.epmet.commons.extappauth.bean.ExternalAppRequestParam; | 
			
		
	
		
			
				
					|  |  |  | import com.epmet.commons.tools.enums.EnvEnum; | 
			
		
	
		
			
				
					|  |  |  | import com.epmet.commons.tools.exception.RenException; | 
			
		
	
		
			
				
					|  |  |  | import com.epmet.commons.tools.redis.RedisKeys; | 
			
		
	
		
			
				
					|  |  |  | import com.epmet.commons.tools.redis.RedisUtils; | 
			
		
	
		
			
				
					|  |  |  | import com.epmet.commons.tools.utils.DateUtils; | 
			
		
	
		
			
				
					|  |  |  | import com.epmet.commons.tools.utils.HttpClientManager; | 
			
		
	
		
			
				
					|  |  |  | import com.epmet.commons.tools.utils.Result; | 
			
		
	
		
			
				
					|  |  |  | import com.epmet.commons.tools.validator.ValidatorUtils; | 
			
		
	
		
			
				
					|  |  |  | import com.epmet.constant.CalculateStatus; | 
			
		
	
		
			
				
					|  |  |  | import com.epmet.dto.indexcal.CalculateCommonFormDTO; | 
			
		
	
		
			
				
					|  |  |  | import com.epmet.model.CalculateFlagModel; | 
			
		
	
		
			
				
					|  |  |  | import com.epmet.service.evaluationindex.indexcal.CpcIndexCalculateService; | 
			
		
	
		
			
				
					|  |  |  | import com.epmet.service.evaluationindex.indexcal.IndexCalculateService; | 
			
		
	
		
			
				
					|  |  |  | import com.epmet.util.DimIdGenerator; | 
			
		
	
	
		
			
				
					|  |  | @ -25,6 +29,7 @@ import javax.annotation.PreDestroy; | 
			
		
	
		
			
				
					|  |  |  | import java.util.Date; | 
			
		
	
		
			
				
					|  |  |  | import java.util.HashMap; | 
			
		
	
		
			
				
					|  |  |  | import java.util.Map; | 
			
		
	
		
			
				
					|  |  |  | import java.util.Set; | 
			
		
	
		
			
				
					|  |  |  | import java.util.concurrent.*; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | /** | 
			
		
	
	
		
			
				
					|  |  | @ -59,20 +64,43 @@ public class IndexCalculateController { | 
			
		
	
		
			
				
					|  |  |  |     private Map<String, Future> futureMap = new HashMap<>(); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     @PreDestroy | 
			
		
	
		
			
				
					|  |  |  |     public void clearDataCalFlag() { | 
			
		
	
		
			
				
					|  |  |  |         // 实例销毁之前,将正在本实例中执行计算的客户列表的计算状态清空
 | 
			
		
	
		
			
				
					|  |  |  |     public void saveCalStatus() { | 
			
		
	
		
			
				
					|  |  |  |         // 实例销毁之前,将正在本实例中执行计算的客户列表的计算状态修改为pendding,等待其他实例重新计算
 | 
			
		
	
		
			
				
					|  |  |  |         futureMap.forEach((customerId, future) -> { | 
			
		
	
		
			
				
					|  |  |  |             redisUtils.delete(RedisKeys.getCustomerStatsCalFlag(customerId)); | 
			
		
	
		
			
				
					|  |  |  |             CalculateFlagModel flag = (CalculateFlagModel) redisUtils.get(RedisKeys.getCustomerStatsCalFlag(customerId)); | 
			
		
	
		
			
				
					|  |  |  |             flag.setStatus(CalculateStatus.PENDDING); | 
			
		
	
		
			
				
					|  |  |  |             redisUtils.set(RedisKeys.getCustomerStatsCalFlag(customerId), flag); | 
			
		
	
		
			
				
					|  |  |  |             log.info("客户【%s】正在执行计算,实例发生重启,修改计算状态为:calculation->pendding", customerId); | 
			
		
	
		
			
				
					|  |  |  |         }); | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     /** | 
			
		
	
		
			
				
					|  |  |  |      * 处理暂停中的计算 | 
			
		
	
		
			
				
					|  |  |  |      */ | 
			
		
	
		
			
				
					|  |  |  |     @PostMapping("process-pendding-cals") | 
			
		
	
		
			
				
					|  |  |  |     public Result processPenddingCalculate() { | 
			
		
	
		
			
				
					|  |  |  |         String keyPrefix = RedisKeys.getCustomerStatsCalKeyPrefix(); | 
			
		
	
		
			
				
					|  |  |  |         Set<String> calFlagKeys = redisUtils.keys(keyPrefix.concat("*")); | 
			
		
	
		
			
				
					|  |  |  |         calFlagKeys.forEach(key -> { | 
			
		
	
		
			
				
					|  |  |  |             CalculateFlagModel flag = (CalculateFlagModel) redisUtils.get(key); | 
			
		
	
		
			
				
					|  |  |  |             if (flag != null && CalculateStatus.PENDDING.equals(flag.getStatus())) { | 
			
		
	
		
			
				
					|  |  |  |                 // 找到状态是pendding的key,执行计算
 | 
			
		
	
		
			
				
					|  |  |  |                 CalculateCommonFormDTO form = new CalculateCommonFormDTO(); | 
			
		
	
		
			
				
					|  |  |  |                 form.setCustomerId(flag.getForm().getCustomerId()); | 
			
		
	
		
			
				
					|  |  |  |                 form.setMonthId(flag.getForm().getMonthId()); | 
			
		
	
		
			
				
					|  |  |  |                 indexCalculate(form); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |         }); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         return new Result(); | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     /** | 
			
		
	
		
			
				
					|  |  |  |      * 按照客户计算所有指标(按照月份) | 
			
		
	
		
			
				
					|  |  |  |      * | 
			
		
	
		
			
				
					|  |  |  |      * @param formDTO | 
			
		
	
		
			
				
					|  |  |  |      * @return com.epmet.commons.tools.utils.Result | 
			
		
	
		
			
				
					|  |  |  |      * @Author zhangyong | 
			
		
	
		
			
				
					|  |  |  |      * @Author zhangyongç | 
			
		
	
		
			
				
					|  |  |  |      * @Date 10:52 2020-08-20 | 
			
		
	
		
			
				
					|  |  |  |      **/ | 
			
		
	
		
			
				
					|  |  |  |     @ExternalAppRequestAuth | 
			
		
	
	
		
			
				
					|  |  | @ -80,34 +108,66 @@ public class IndexCalculateController { | 
			
		
	
		
			
				
					|  |  |  |     public Result<Boolean> indexCalculate(ExternalAppRequestParam externalAppRequestParam, @RequestBody CalculateCommonFormDTO formDTO) { | 
			
		
	
		
			
				
					|  |  |  |         String customerId = externalAppRequestParam.getCustomerId(); | 
			
		
	
		
			
				
					|  |  |  |         //String customerId = "epmettest";
 | 
			
		
	
		
			
				
					|  |  |  |         Boolean executing = (Boolean) redisUtils.get(RedisKeys.getCustomerStatsCalFlag(customerId)); | 
			
		
	
		
			
				
					|  |  |  |         if (executing == null || !executing) { | 
			
		
	
		
			
				
					|  |  |  |         formDTO.setCustomerId(customerId); | 
			
		
	
		
			
				
					|  |  |  |         indexCalculate(formDTO); | 
			
		
	
		
			
				
					|  |  |  |         return new Result<Boolean>().ok(true); | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     /** | 
			
		
	
		
			
				
					|  |  |  |      * 指标计算 | 
			
		
	
		
			
				
					|  |  |  |      * @param formDTO | 
			
		
	
		
			
				
					|  |  |  |      */ | 
			
		
	
		
			
				
					|  |  |  |     private void indexCalculate(CalculateCommonFormDTO formDTO) { | 
			
		
	
		
			
				
					|  |  |  |         CalculateFlagModel executeFlag = (CalculateFlagModel) redisUtils.get(RedisKeys.getCustomerStatsCalFlag(formDTO.getCustomerId())); | 
			
		
	
		
			
				
					|  |  |  |         if (executeFlag == null || !CalculateStatus.CALCULATING.equals(executeFlag.getStatus())) { | 
			
		
	
		
			
				
					|  |  |  |             // 可以计算
 | 
			
		
	
		
			
				
					|  |  |  |             synchronized (statsCalLock) { | 
			
		
	
		
			
				
					|  |  |  |                 Boolean executing2 = (Boolean) redisUtils.get(RedisKeys.getCustomerStatsCalFlag(customerId)); | 
			
		
	
		
			
				
					|  |  |  |                 if (executing2 != null && executing2) { | 
			
		
	
		
			
				
					|  |  |  |                     log.error(String.format("该客户正在执行计算,请勿重复提交计算请求。", customerId)); | 
			
		
	
		
			
				
					|  |  |  |                     return new Result<Boolean>().ok(false); | 
			
		
	
		
			
				
					|  |  |  |                 CalculateFlagModel executingFlag2 = (CalculateFlagModel) redisUtils.get(RedisKeys.getCustomerStatsCalFlag(formDTO.getCustomerId())); | 
			
		
	
		
			
				
					|  |  |  |                 if (executingFlag2 != null && CalculateStatus.CALCULATING.equals(executingFlag2.getStatus())) { | 
			
		
	
		
			
				
					|  |  |  |                     //log.error(String.format("客户【%s】正在执行计算,请勿重复提交计算请求。", customerId));
 | 
			
		
	
		
			
				
					|  |  |  |                     throw new RenException(String.format("客户【%s】正在执行计算,请勿重复提交计算请求。", formDTO.getCustomerId())); | 
			
		
	
		
			
				
					|  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |                 Future<?> future = singleThreadPool.submit(() -> { | 
			
		
	
		
			
				
					|  |  |  |                     formDTO.setCustomerId(customerId); | 
			
		
	
		
			
				
					|  |  |  |                     long start = System.currentTimeMillis(); | 
			
		
	
		
			
				
					|  |  |  |                     Boolean aBoolean = indexCalculateService.indexCalculate(formDTO); | 
			
		
	
		
			
				
					|  |  |  |                     if (aBoolean) { | 
			
		
	
		
			
				
					|  |  |  |                         log.error("客户Id:{},全部指标计算完成,总耗时:{}秒", customerId, (System.currentTimeMillis() - start) / 1000); | 
			
		
	
		
			
				
					|  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |                     redisUtils.delete(RedisKeys.getCustomerStatsCalFlag(customerId)); | 
			
		
	
		
			
				
					|  |  |  |                     futureMap.remove(customerId); | 
			
		
	
		
			
				
					|  |  |  |                 }); | 
			
		
	
		
			
				
					|  |  |  |                 futureMap.put(customerId, future); | 
			
		
	
		
			
				
					|  |  |  |                 redisUtils.set(RedisKeys.getCustomerStatsCalFlag(customerId), true); | 
			
		
	
		
			
				
					|  |  |  |                 // 提交异步计算
 | 
			
		
	
		
			
				
					|  |  |  |                 submitCalculate(formDTO); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |         } else { | 
			
		
	
		
			
				
					|  |  |  |             log.error(String.format("该客户正在执行计算,请勿重复提交计算请求。", customerId)); | 
			
		
	
		
			
				
					|  |  |  |             return new Result<Boolean>().ok(false); | 
			
		
	
		
			
				
					|  |  |  |             throw new RenException(String.format("客户【%s】正在执行计算,请勿重复提交计算请求。", formDTO.getCustomerId())); | 
			
		
	
		
			
				
					|  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     /** | 
			
		
	
		
			
				
					|  |  |  |      * 提交异步计算 | 
			
		
	
		
			
				
					|  |  |  |      * @param formDTO | 
			
		
	
		
			
				
					|  |  |  |      * @return | 
			
		
	
		
			
				
					|  |  |  |      */ | 
			
		
	
		
			
				
					|  |  |  |     private void submitCalculate(CalculateCommonFormDTO formDTO) { | 
			
		
	
		
			
				
					|  |  |  |         Future<?> future = singleThreadPool.submit(() -> { | 
			
		
	
		
			
				
					|  |  |  |             long start = System.currentTimeMillis(); | 
			
		
	
		
			
				
					|  |  |  |             Boolean aBoolean = indexCalculateService.indexCalculate(formDTO); | 
			
		
	
		
			
				
					|  |  |  |             if (aBoolean) { | 
			
		
	
		
			
				
					|  |  |  |                 log.error("客户Id:{},全部指标计算完成,总耗时:{}秒", formDTO.getCustomerId(), (System.currentTimeMillis() - start) / 1000); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         return new Result<Boolean>().ok(true); | 
			
		
	
		
			
				
					|  |  |  |             redisUtils.delete(RedisKeys.getCustomerStatsCalFlag(formDTO.getCustomerId())); | 
			
		
	
		
			
				
					|  |  |  |             futureMap.remove(formDTO.getCustomerId()); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |             //测试代码
 | 
			
		
	
		
			
				
					|  |  |  |             //try {
 | 
			
		
	
		
			
				
					|  |  |  |             //    Thread.sleep(20000l);
 | 
			
		
	
		
			
				
					|  |  |  |             //    System.out.println(System.currentTimeMillis());
 | 
			
		
	
		
			
				
					|  |  |  |             //} catch (InterruptedException e) {
 | 
			
		
	
		
			
				
					|  |  |  |             //    e.printStackTrace();
 | 
			
		
	
		
			
				
					|  |  |  |             //}
 | 
			
		
	
		
			
				
					|  |  |  |             //redisUtils.delete(RedisKeys.getCustomerStatsCalFlag(formDTO.getCustomerId()));
 | 
			
		
	
		
			
				
					|  |  |  |             //futureMap.remove(formDTO.getCustomerId());
 | 
			
		
	
		
			
				
					|  |  |  |         }); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         futureMap.put(formDTO.getCustomerId(), future); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         CalculateFlagModel flag = new CalculateFlagModel(); | 
			
		
	
		
			
				
					|  |  |  |         flag.setStatus(CalculateStatus.CALCULATING); | 
			
		
	
		
			
				
					|  |  |  |         flag.setForm(formDTO); | 
			
		
	
		
			
				
					|  |  |  |         redisUtils.set(RedisKeys.getCustomerStatsCalFlag(formDTO.getCustomerId()), flag); | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     /** | 
			
		
	
	
		
			
				
					|  |  | @ -126,7 +186,7 @@ public class IndexCalculateController { | 
			
		
	
		
			
				
					|  |  |  |             future.cancel(true); | 
			
		
	
		
			
				
					|  |  |  |             redisUtils.delete(RedisKeys.getCustomerStatsCalFlag(customerId)); | 
			
		
	
		
			
				
					|  |  |  |             futureMap.remove(customerId); | 
			
		
	
		
			
				
					|  |  |  |             HttpClientManager.getInstance().sendAlarmMsg(String.format("数据统计服务-中止计算成功,customerId:%s", customerId)); | 
			
		
	
		
			
				
					|  |  |  |             HttpClientManager.getInstance().sendAlarmMsg(String.format(EnvEnum.getCurrentEnv().getName() + "数据统计服务-中止计算成功,customerId:%s", customerId)); | 
			
		
	
		
			
				
					|  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |         return new Result(); | 
			
		
	
		
			
				
					|  |  |  |     } | 
			
		
	
	
		
			
				
					|  |  | @ -135,7 +195,7 @@ public class IndexCalculateController { | 
			
		
	
		
			
				
					|  |  |  |     public Result<Boolean> calculateAll(@RequestBody CalculateCommonFormDTO formDTO) { | 
			
		
	
		
			
				
					|  |  |  |         long start = System.currentTimeMillis(); | 
			
		
	
		
			
				
					|  |  |  |         Boolean aBoolean = indexCalculateService.indexCalculate(formDTO); | 
			
		
	
		
			
				
					|  |  |  |         HttpClientManager.getInstance().sendAlarmMsg("客户Id:" + formDTO.getCustomerId() + ",calculateAll全部指标计算完成,是否成功:" + aBoolean + ",总耗时:" + (System.currentTimeMillis() - start) / 1000 + "秒"); | 
			
		
	
		
			
				
					|  |  |  |         HttpClientManager.getInstance().sendAlarmMsg(EnvEnum.getCurrentEnv().getName() + "客户Id:" + formDTO.getCustomerId() + ",calculateAll全部指标计算完成,是否成功:" + aBoolean + ",总耗时:" + (System.currentTimeMillis() - start) / 1000 + "秒"); | 
			
		
	
		
			
				
					|  |  |  |         if (aBoolean) { | 
			
		
	
		
			
				
					|  |  |  |             return new Result<Boolean>().ok(true); | 
			
		
	
		
			
				
					|  |  |  |         } | 
			
		
	
	
		
			
				
					|  |  | 
 |