|
|
@@ -16,8 +16,10 @@ import com.hdkj.lt.bf.entity.FhzgAutoTaskPlan;
|
|
|
import com.hdkj.lt.bf.entity.FhzgAutoTaskPlanDetail;
|
|
|
import com.hdkj.lt.bf.service.*;
|
|
|
import com.hdkj.lt.core.bizms.modle.po.DwdShbDsFeederBase;
|
|
|
+import com.hdkj.lt.feign.ISimulationPlatformApiClient;
|
|
|
import com.hdkj.lt.feign.IPlanCreateClient;
|
|
|
import com.hdkj.lt.modle.dto.plan.AcceptPlanPowerCutListRequest;
|
|
|
+import com.hdkj.lt.modle.dto.simulation.ElectricalModelRequest;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.apache.commons.lang3.StringUtils;
|
|
|
@@ -31,6 +33,7 @@ import java.time.LocalDate;
|
|
|
import java.time.LocalDateTime;
|
|
|
import java.time.temporal.TemporalAdjusters;
|
|
|
import java.util.*;
|
|
|
+import java.util.concurrent.*;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
/**
|
|
|
@@ -44,14 +47,26 @@ import java.util.stream.Collectors;
|
|
|
public class AutoTaskServiceImpl implements AutoTaskService {
|
|
|
|
|
|
private final FhzgAutoTaskPlanService autoTaskPlanService;
|
|
|
-
|
|
|
private final FhzgAutoTaskCountryInfoService autoTaskCountryInfoService;
|
|
|
-
|
|
|
private final FhzgAutoTaskPlanDetailService autoTaskPlanDetailService;
|
|
|
-
|
|
|
private final FhzgAutoTaskFeederChangeService autoTaskFeederChangeService;
|
|
|
-
|
|
|
private final IPlanCreateClient planCreateClient;
|
|
|
+ private final ISimulationPlatformApiClient simulationPlatformApiClient;
|
|
|
+ private final FhzgElectricalModelSectionService electricalModelSectionService;
|
|
|
+
|
|
|
+ // ==================== 电气模型采集线程池 ====================
|
|
|
+ private static final ThreadPoolExecutor ELECTRICAL_MODEL_POOL = new ThreadPoolExecutor(
|
|
|
+ 10, 20, 60, TimeUnit.SECONDS,
|
|
|
+ new LinkedBlockingQueue<>(200),
|
|
|
+ new ThreadFactory() {
|
|
|
+ private int count = 0;
|
|
|
+ @Override
|
|
|
+ public Thread newThread(Runnable r) {
|
|
|
+ return new Thread(r, "elec-model-" + (++count));
|
|
|
+ }
|
|
|
+ },
|
|
|
+ new ThreadPoolExecutor.CallerRunsPolicy()
|
|
|
+ );
|
|
|
|
|
|
@Override
|
|
|
public List<AutoTaskFeederResponse> getCountryStatistic(AutoTaskQueryRequest request) {
|
|
|
@@ -468,4 +483,118 @@ public class AutoTaskServiceImpl implements AutoTaskService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // ==================== 电气模型定时采集 ====================
|
|
|
+
|
|
|
+ /** 最大重试次数 */
|
|
|
+ private static final int MAX_RETRY = 3;
|
|
|
+ /** 失败率阈值:超过此比例不触发后续计算 */
|
|
|
+ private static final double FAIL_THRESHOLD = 1;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 定时采集电气模型数据(每15分钟)
|
|
|
+ * 入口方法,可由定时任务或手动调用触发
|
|
|
+ *
|
|
|
+ * @param cityCode 地市编码
|
|
|
+ * @param feederList 馈线ID列表
|
|
|
+ */
|
|
|
+ public void collectElectricalModel(String cityCode, List<String> feederList) {
|
|
|
+ if (feederList == null || feederList.isEmpty()) {
|
|
|
+ log.warn("电气模型采集-馈线列表为空, cityCode={}", cityCode);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("电气模型采集-开始, cityCode={}, 馈线数={}", cityCode, feederList.size());
|
|
|
+ long start = System.currentTimeMillis();
|
|
|
+
|
|
|
+ // 1. 并发调用推演平台,每条馈线一个CompletableFuture
|
|
|
+ List<CompletableFuture<String>> futures = new ArrayList<>();
|
|
|
+ for (String feederId : feederList) {
|
|
|
+ CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
|
|
|
+ return collectSingleFeederWithRetry(cityCode, feederId);
|
|
|
+ }, ELECTRICAL_MODEL_POOL);
|
|
|
+ futures.add(future);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 等待全部完成
|
|
|
+ CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
|
|
|
+
|
|
|
+ // 3. 收集结果
|
|
|
+ int successCount = 0;
|
|
|
+ int failCount = 0;
|
|
|
+ List<String> failedFeederIds = new ArrayList<>();
|
|
|
+
|
|
|
+ for (int i = 0; i < futures.size(); i++) {
|
|
|
+ String feederId = feederList.get(i);
|
|
|
+ try {
|
|
|
+ String jsonStr = futures.get(i).get();
|
|
|
+ if (jsonStr != null) {
|
|
|
+ // 4. 入库
|
|
|
+ electricalModelSectionService.saveFromJson(jsonStr);
|
|
|
+ successCount++;
|
|
|
+ } else {
|
|
|
+ failCount++;
|
|
|
+ failedFeederIds.add(feederId);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ failCount++;
|
|
|
+ failedFeederIds.add(feederId);
|
|
|
+ log.error("电气模型采集-入库失败, feederId={}", feederId, e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ long cost = System.currentTimeMillis() - start;
|
|
|
+ double failRate = feederList.isEmpty() ? 0 : (double) failCount / feederList.size();
|
|
|
+
|
|
|
+ log.info("电气模型采集-完成, cityCode={}, 成功={}, 失败={}, 耗时={}ms, 失败率={}",
|
|
|
+ cityCode, successCount, failCount, cost, String.format("%.2f%%", failRate * 100));
|
|
|
+
|
|
|
+ if (!failedFeederIds.isEmpty()) {
|
|
|
+ log.warn("电气模型采集-失败馈线: {}", failedFeederIds);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 5. 失败率过高则不触发后续计算
|
|
|
+ if (failRate >= FAIL_THRESHOLD) {
|
|
|
+ log.error("电气模型采集-失败率超过{}%, 不触发指标计算, cityCode={}", (int)(FAIL_THRESHOLD * 100), cityCode);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 6. TODO: 发送MQ消息触发指标计算
|
|
|
+ // rocketMQTemplate.sendAsyncMessage(...);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 采集单条馈线(带重试)
|
|
|
+ * @return 原始JSON字符串,失败返回null
|
|
|
+ */
|
|
|
+ private String collectSingleFeederWithRetry(String cityCode, String feederId) {
|
|
|
+ for (int attempt = 1; attempt <= MAX_RETRY; attempt++) {
|
|
|
+ try {
|
|
|
+ ElectricalModelRequest request = new ElectricalModelRequest();
|
|
|
+ request.setCityId(cityCode);
|
|
|
+ request.setFeederList(Collections.singletonList(feederId));
|
|
|
+
|
|
|
+ String jsonStr = simulationPlatformApiClient.getElectricalModel(request);
|
|
|
+ if (jsonStr != null) {
|
|
|
+ log.debug("电气模型采集-成功, feederId={}, attempt={}", feederId, attempt);
|
|
|
+ return jsonStr;
|
|
|
+ }
|
|
|
+ log.warn("电气模型采集-返回null, feederId={}, attempt={}", feederId, attempt);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("电气模型采集-调用异常, feederId={}, attempt={}/{}, error={}",
|
|
|
+ feederId, attempt, MAX_RETRY, e.getMessage());
|
|
|
+ }
|
|
|
+ // 递增等待: 1s, 3s, 5s
|
|
|
+ if (attempt < MAX_RETRY) {
|
|
|
+ try {
|
|
|
+ Thread.sleep(1000L * (2 * attempt - 1));
|
|
|
+ } catch (InterruptedException ie) {
|
|
|
+ Thread.currentThread().interrupt();
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ log.error("电气模型采集-重试耗尽, feederId={}", feederId);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
}
|