From 63b01db83d9aad8a15276b4236a9a22e4aeef065 Mon Sep 17 00:00:00 2001
From: Junjie <fallin.jie@qq.com>
Date: 星期二, 05 五月 2026 12:30:59 +0800
Subject: [PATCH] # Agent数据分析V3.0.1.7
---
src/main/java/com/zy/ai/service/impl/AutoTuneApplyServiceImpl.java | 900 ++++++++++++++++++++++++++++++++++++++++++++++++++---------
1 files changed, 755 insertions(+), 145 deletions(-)
diff --git a/src/main/java/com/zy/ai/service/impl/AutoTuneApplyServiceImpl.java b/src/main/java/com/zy/ai/service/impl/AutoTuneApplyServiceImpl.java
index 3143610..ab23dd9 100644
--- a/src/main/java/com/zy/ai/service/impl/AutoTuneApplyServiceImpl.java
+++ b/src/main/java/com/zy/ai/service/impl/AutoTuneApplyServiceImpl.java
@@ -5,6 +5,7 @@
import com.zy.ai.domain.autotune.AutoTuneApplyRequest;
import com.zy.ai.domain.autotune.AutoTuneApplyResult;
import com.zy.ai.domain.autotune.AutoTuneChangeCommand;
+import com.zy.ai.domain.autotune.AutoTuneControlModeSnapshot;
import com.zy.ai.domain.autotune.AutoTuneJobStatus;
import com.zy.ai.domain.autotune.AutoTuneRuleDefinition;
import com.zy.ai.domain.autotune.AutoTuneTargetType;
@@ -14,30 +15,52 @@
import com.zy.ai.service.AiAutoTuneChangeService;
import com.zy.ai.service.AiAutoTuneJobService;
import com.zy.ai.service.AutoTuneApplyService;
+import com.zy.ai.service.AutoTuneControlModeService;
import com.zy.asrs.entity.BasCrnp;
import com.zy.asrs.entity.BasDualCrnp;
import com.zy.asrs.entity.BasStation;
-import com.zy.asrs.entity.StationFlowCapacity;
+import com.zy.asrs.entity.WrkMast;
import com.zy.asrs.service.BasCrnpService;
import com.zy.asrs.service.BasDualCrnpService;
import com.zy.asrs.service.BasStationService;
-import com.zy.asrs.service.StationFlowCapacityService;
+import com.zy.asrs.service.WrkMastService;
+import com.zy.common.utils.RedisUtil;
+import com.zy.core.enums.RedisKeyType;
+import com.zy.core.enums.WrkStsType;
import com.zy.system.entity.Config;
import com.zy.system.service.ConfigService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.support.TransactionTemplate;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Date;
+import java.util.HashSet;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
+import java.util.UUID;
@Service("autoTuneApplyService")
public class AutoTuneApplyServiceImpl implements AutoTuneApplyService {
+ private static final Logger LOGGER = LoggerFactory.getLogger(AutoTuneApplyServiceImpl.class);
private static final String PROMPT_SCENE_CODE = "auto_tune_apply";
- private static final String DIRECTION_OUT = "OUT";
+ private static final long APPLY_LOCK_SECONDS = 120L;
+ private static final String APPLY_LOCK_BUSY_REASON = "鐢宠璋冨弬閿佸け璐ワ紝閿佷笉鍙敤锛屽彲鑳藉凡鏈変换鍔℃垨 Redis 寮傚父";
+ private static final String ANALYSIS_ONLY_REJECT_REASON = "浠呭垎鏋愭ā寮忕姝㈠疄闄呭簲鐢�/鍥炴粴锛屾湭淇敼杩愯鍙傛暟";
+ private static final List<Long> FINAL_WRK_STS_LIST = Arrays.asList(
+ WrkStsType.COMPLETE_INBOUND.sts,
+ WrkStsType.SETTLE_INBOUND.sts,
+ WrkStsType.COMPLETE_OUTBOUND.sts,
+ WrkStsType.SETTLE_OUTBOUND.sts,
+ WrkStsType.COMPLETE_LOC_MOVE.sts,
+ WrkStsType.COMPLETE_CRN_MOVE.sts
+ );
@Autowired
private AiAutoTuneJobService aiAutoTuneJobService;
@@ -46,90 +69,236 @@
@Autowired
private ConfigService configService;
@Autowired
+ private AutoTuneControlModeService autoTuneControlModeService;
+ @Autowired
private BasStationService basStationService;
@Autowired
private BasCrnpService basCrnpService;
@Autowired
private BasDualCrnpService basDualCrnpService;
@Autowired
- private StationFlowCapacityService stationFlowCapacityService;
+ private WrkMastService wrkMastService;
+ @Autowired
+ private PlatformTransactionManager transactionManager;
+ @Autowired
+ private RedisUtil redisUtil;
@Override
- @Transactional
public AutoTuneApplyResult apply(AutoTuneApplyRequest request) {
AutoTuneApplyRequest safeRequest = request == null ? new AutoTuneApplyRequest() : request;
+ AutoTuneControlModeSnapshot controlMode = currentControlModeSnapshot();
boolean dryRun = Boolean.TRUE.equals(safeRequest.getDryRun());
Date now = new Date();
AiAutoTuneJob job = createJob(safeRequest, dryRun, now);
- aiAutoTuneJobService.save(job);
- List<ValidatedChange> validatedChanges = validateChanges(safeRequest, dryRun, now);
- boolean hasRejectedChange = hasRejectedChange(validatedChanges);
- if (!dryRun && hasRejectedChange) {
- markAcceptedChangesAsBatchRejected(validatedChanges);
+ if (dryRun) {
+ return applyDryRun(safeRequest, job, now, controlMode);
}
- if (!dryRun && !hasRejectedChange) {
- applyValidatedChanges(validatedChanges);
+ if (isAnalysisOnly(controlMode)) {
+ return rejectRealApplyForAnalysisOnly(safeRequest, job, now, controlMode);
+ }
+ return applyRealWithLock(safeRequest, job, now, controlMode);
+ }
+
+ private AutoTuneApplyResult applyDryRun(AutoTuneApplyRequest request,
+ AiAutoTuneJob job,
+ Date now,
+ AutoTuneControlModeSnapshot controlMode) {
+ List<ValidatedChange> validatedChanges = validateChanges(request, true, now);
+ ApplyPersistenceResult persistenceResult = persistApplyResultInTransaction(
+ job,
+ request,
+ validatedChanges,
+ true,
+ now,
+ false
+ );
+ return buildResult(job, persistenceResult.getAuditChanges(), true, controlMode);
+ }
+
+ private AutoTuneApplyResult applyRealWithLock(AutoTuneApplyRequest request,
+ AiAutoTuneJob job,
+ Date now,
+ AutoTuneControlModeSnapshot controlMode) {
+ if (request.getChanges() == null || request.getChanges().isEmpty()) {
+ ApplyPersistenceResult persistenceResult = persistApplyResultInTransaction(
+ job,
+ request,
+ new ArrayList<>(),
+ false,
+ now,
+ false
+ );
+ return buildResult(job, persistenceResult.getAuditChanges(), false, controlMode);
}
- List<AiAutoTuneChange> auditChanges = buildAuditChanges(job.getId(), validatedChanges, now);
- if (!auditChanges.isEmpty()) {
- aiAutoTuneChangeService.saveBatch(auditChanges);
+ String lockKey = RedisKeyType.AI_AUTO_TUNE_APPLY_LOCK.key;
+ String lockToken = UUID.randomUUID().toString();
+ if (!redisUtil.trySetStringIfAbsent(lockKey, lockToken, APPLY_LOCK_SECONDS)) {
+ return rejectRealApplyForUnavailableLock(request, job, now, lockKey, controlMode);
}
- finishJob(job, safeRequest, auditChanges, dryRun, now);
- aiAutoTuneJobService.updateById(job);
- return buildResult(job, auditChanges, dryRun);
+
+ try {
+ List<ValidatedChange> validatedChanges = validateChanges(request, false, now);
+ boolean hasRejectedChange = hasRejectedChange(validatedChanges);
+ if (hasRejectedChange) {
+ markAcceptedChangesAsBatchRejected(validatedChanges);
+ }
+ if (hasRejectedChange) {
+ ApplyPersistenceResult persistenceResult = persistApplyResultInTransaction(
+ job,
+ request,
+ validatedChanges,
+ false,
+ now,
+ false
+ );
+ return buildResult(job, persistenceResult.getAuditChanges(), false, controlMode);
+ }
+
+ try {
+ ApplyPersistenceResult persistenceResult = persistApplyResultInTransaction(
+ job,
+ request,
+ validatedChanges,
+ false,
+ now,
+ true
+ );
+ refreshSystemConfigCacheSafely(persistenceResult);
+ return buildResult(job, persistenceResult.getAuditChanges(), false, controlMode);
+ } catch (RuntimeException exception) {
+ markWriteFailure(validatedChanges, exception);
+ Date failureNow = new Date();
+ AiAutoTuneJob failureJob = createJob(request, false, failureNow);
+ ApplyPersistenceResult persistenceResult = persistApplyResultInTransaction(
+ failureJob,
+ request,
+ validatedChanges,
+ false,
+ failureNow,
+ false
+ );
+ return buildResult(failureJob, persistenceResult.getAuditChanges(), false, controlMode);
+ }
+ } finally {
+ redisUtil.compareAndDelete(lockKey, lockToken);
+ }
+ }
+
+ private AutoTuneApplyResult rejectRealApplyForUnavailableLock(AutoTuneApplyRequest request,
+ AiAutoTuneJob job,
+ Date now,
+ String lockKey,
+ AutoTuneControlModeSnapshot controlMode) {
+ boolean lockKeyExists = redisUtil.hasKey(lockKey);
+ LOGGER.warn("鐢宠AI鑷姩璋冨弬 apply 閿佸け璐ワ紝lockKey={}, lockKeyExists={}", lockKey, lockKeyExists);
+ List<ValidatedChange> validatedChanges = buildLockBusyChanges(request);
+ ApplyPersistenceResult persistenceResult = persistApplyResultInTransaction(
+ job,
+ request,
+ validatedChanges,
+ false,
+ now,
+ false
+ );
+ return buildResult(job, persistenceResult.getAuditChanges(), false, controlMode);
+ }
+
+ private AutoTuneApplyResult rejectRealApplyForAnalysisOnly(AutoTuneApplyRequest request,
+ AiAutoTuneJob job,
+ Date now,
+ AutoTuneControlModeSnapshot controlMode) {
+ ApplyPersistenceResult persistenceResult = persistAnalysisOnlyApplyRejectionInTransaction(job, request, now);
+ AutoTuneApplyResult result = buildResult(job, persistenceResult.getAuditChanges(), false, controlMode);
+ result.setAnalysisOnly(true);
+ result.setNoApply(true);
+ return result;
+ }
+
+ private List<ValidatedChange> buildLockBusyChanges(AutoTuneApplyRequest request) {
+ List<ValidatedChange> validatedChanges = new ArrayList<>();
+ if (request.getChanges() == null || request.getChanges().isEmpty()) {
+ return validatedChanges;
+ }
+ for (AutoTuneChangeCommand command : request.getChanges()) {
+ ValidatedChange validatedChange = new ValidatedChange(command);
+ validatedChange.fail(APPLY_LOCK_BUSY_REASON);
+ validatedChanges.add(validatedChange);
+ }
+ return validatedChanges;
}
@Override
- @Transactional
public AutoTuneApplyResult rollbackLastSuccessfulJob(String reason) {
+ AutoTuneControlModeSnapshot controlMode = currentControlModeSnapshot();
Date now = new Date();
AiAutoTuneJob rollbackJob = createRollbackJob(reason, now);
- aiAutoTuneJobService.save(rollbackJob);
-
- List<AiAutoTuneChange> sourceChanges = findLatestSuccessfulChanges();
- if (sourceChanges.isEmpty()) {
- rollbackJob.setStatus(AutoTuneJobStatus.REJECTED.getCode());
- rollbackJob.setFinishTime(now);
- rollbackJob.setRejectCount(0);
- rollbackJob.setSuccessCount(0);
- rollbackJob.setSummary("鏈壘鍒板彲鍥炴粴鐨勬垚鍔熻皟鍙傝褰�");
- rollbackJob.setErrorMessage("鏈壘鍒板彲鍥炴粴鐨勬垚鍔熻皟鍙傝褰�");
- aiAutoTuneJobService.updateById(rollbackJob);
- return buildResult(rollbackJob, new ArrayList<>(), false);
+ if (isAnalysisOnly(controlMode)) {
+ return rejectRollbackForAnalysisOnly(rollbackJob, now, controlMode);
}
- List<AiAutoTuneChange> rollbackChanges = new ArrayList<>();
- boolean refreshedConfigCache = false;
- for (AiAutoTuneChange sourceChange : sourceChanges) {
- AiAutoTuneChange rollbackChange = buildRollbackChange(rollbackJob.getId(), sourceChange, now);
- try {
- String currentValue = readCurrentValue(
- sourceChange.getTargetType(),
- sourceChange.getTargetId(),
- sourceChange.getTargetKey()
- );
- rollbackChange.setOldValue(currentValue);
- writeValue(sourceChange.getTargetType(), sourceChange.getTargetId(), sourceChange.getTargetKey(), sourceChange.getOldValue());
- if (AutoTuneTargetType.SYS_CONFIG.getCode().equals(sourceChange.getTargetType())) {
- refreshedConfigCache = true;
- }
- rollbackChange.setAppliedValue(sourceChange.getOldValue());
- rollbackChange.setResultStatus(ChangeStatus.SUCCESS.getCode());
- } catch (Exception exception) {
- rollbackChange.setResultStatus(ChangeStatus.FAILED.getCode());
- rollbackChange.setRejectReason(exception.getMessage());
+ String lockKey = RedisKeyType.AI_AUTO_TUNE_APPLY_LOCK.key;
+ String lockToken = UUID.randomUUID().toString();
+ if (!redisUtil.trySetStringIfAbsent(lockKey, lockToken, APPLY_LOCK_SECONDS)) {
+ return rejectRollbackForUnavailableLock(reason, now, lockKey, controlMode);
+ }
+
+ try {
+ List<AiAutoTuneChange> sourceChanges = findLatestSuccessfulChanges();
+ if (sourceChanges.isEmpty()) {
+ persistNoRollbackSourceJobInTransaction(rollbackJob, now);
+ return buildResult(rollbackJob, new ArrayList<>(), false, controlMode);
}
- rollbackChanges.add(rollbackChange);
+ try {
+ RollbackPersistenceResult persistenceResult = persistRollbackResultInTransaction(
+ rollbackJob,
+ sourceChanges,
+ now
+ );
+ refreshRollbackConfigCacheSafely(persistenceResult);
+ return buildResult(rollbackJob, persistenceResult.getRollbackChanges(), false, controlMode);
+ } catch (RuntimeException exception) {
+ Date failureNow = new Date();
+ AiAutoTuneJob failureJob = createRollbackJob(reason, failureNow);
+ RollbackPersistenceResult persistenceResult = persistFailedRollbackResultInTransaction(
+ failureJob,
+ sourceChanges,
+ exception,
+ failureNow
+ );
+ return buildResult(failureJob, persistenceResult.getRollbackChanges(), false, controlMode);
+ }
+ } finally {
+ redisUtil.compareAndDelete(lockKey, lockToken);
}
- if (refreshedConfigCache) {
- configService.refreshSystemConfigCache();
- }
- aiAutoTuneChangeService.saveBatch(rollbackChanges);
- finishRollbackJob(rollbackJob, rollbackChanges, now);
- aiAutoTuneJobService.updateById(rollbackJob);
- return buildResult(rollbackJob, rollbackChanges, false);
+ }
+
+ private AutoTuneApplyResult rejectRollbackForUnavailableLock(String reason,
+ Date now,
+ String lockKey,
+ AutoTuneControlModeSnapshot controlMode) {
+ boolean lockKeyExists = redisUtil.hasKey(lockKey);
+ LOGGER.warn("鐢宠AI鑷姩璋冨弬 rollback 閿佸け璐ワ紝lockKey={}, lockKeyExists={}", lockKey, lockKeyExists);
+ AiAutoTuneJob rollbackJob = createRollbackJob(reason, now);
+ RollbackPersistenceResult persistenceResult = persistRollbackLockFailureInTransaction(
+ rollbackJob,
+ now
+ );
+ return buildResult(rollbackJob, persistenceResult.getRollbackChanges(), false, controlMode);
+ }
+
+ private AutoTuneApplyResult rejectRollbackForAnalysisOnly(AiAutoTuneJob rollbackJob,
+ Date now,
+ AutoTuneControlModeSnapshot controlMode) {
+ RollbackPersistenceResult persistenceResult = persistAnalysisOnlyRollbackRejectionInTransaction(
+ rollbackJob,
+ now
+ );
+ AutoTuneApplyResult result = buildResult(rollbackJob, persistenceResult.getRollbackChanges(), false, controlMode);
+ result.setAnalysisOnly(true);
+ result.setNoApply(true);
+ return result;
}
private List<ValidatedChange> validateChanges(AutoTuneApplyRequest request, boolean dryRun, Date now) {
@@ -145,31 +314,40 @@
private ValidatedChange validateChange(AutoTuneChangeCommand command, boolean dryRun, Date now) {
ValidatedChange validatedChange = new ValidatedChange(command);
- AutoTuneRuleDefinition.Rule rule = AutoTuneRuleDefinition.findRule(command.getTargetType(), command.getTargetKey());
+ AutoTuneRuleDefinition.Rule rule = AutoTuneRuleDefinition.findRule(
+ validatedChange.getTargetType(),
+ validatedChange.getTargetKey()
+ );
if (rule == null) {
- return validatedChange.reject("涓嶆敮鎸佺殑璋冨弬鐩爣: " + command.getTargetType() + "/" + command.getTargetKey());
+ return validatedChange.reject("涓嶆敮鎸佺殑璋冨弬鐩爣: "
+ + validatedChange.getTargetType() + "/" + validatedChange.getTargetKey());
}
validatedChange.setRule(rule);
- Integer requestedValue = parseRequestedInt(command.getNewValue());
+ Integer requestedValue = parseRequestedInt(validatedChange.getRawRequestedValue());
if (requestedValue == null) {
- return validatedChange.reject(command.getTargetKey() + " 蹇呴』涓烘暣鏁�");
+ return validatedChange.reject(validatedChange.getTargetKey() + " 蹇呴』涓烘暣鏁�");
}
validatedChange.setRequestedIntValue(requestedValue);
validatedChange.setRequestedValue(String.valueOf(requestedValue));
- CurrentValue currentValue = readCurrentValueForValidation(command, rule);
+ CurrentValue currentValue = readCurrentValueForValidation(validatedChange, rule);
if (currentValue.getRejectReason() != null) {
return validatedChange.reject(currentValue.getRejectReason());
}
validatedChange.setOldValue(currentValue.getOldValue());
- Integer maxValue = resolveMaxValue(command, rule, requestedValue);
- if (maxValue == null) {
- return validatedChange.reject("绔欑偣 " + command.getTargetId() + " 缂哄皯 OUT 鏂瑰悜 bufferCapacity锛屾棤娉曡瘉鏄� outTaskLimit 涓婇檺");
+ Integer maxValue = resolveMaxValue(validatedChange, rule, requestedValue);
+ if (requestedValue < rule.getMinValue()) {
+ if (maxValue != null) {
+ return validatedChange.reject(validatedChange.getTargetKey() + " 蹇呴』鍦� "
+ + rule.getMinValue() + "~" + maxValue + " 鑼冨洿鍐�");
+ }
+ return validatedChange.reject(validatedChange.getTargetKey() + " 蹇呴』涓嶅皬浜� " + rule.getMinValue());
}
- if (requestedValue < rule.getMinValue() || requestedValue > maxValue) {
- return validatedChange.reject(command.getTargetKey() + " 蹇呴』鍦� " + rule.getMinValue() + "~" + maxValue + " 鑼冨洿鍐�");
+ if (maxValue != null && requestedValue > maxValue) {
+ return validatedChange.reject(validatedChange.getTargetKey() + " 蹇呴』鍦� "
+ + rule.getMinValue() + "~" + maxValue + " 鑼冨洿鍐�");
}
if (Objects.equals(currentValue.getNumericValue(), requestedValue)) {
@@ -177,10 +355,10 @@
}
int step = Math.abs(requestedValue - currentValue.getNumericValue());
if (step > rule.getMaxStep()) {
- return validatedChange.reject(command.getTargetKey() + " 鍗曟璋冩暣姝ラ暱涓嶈兘瓒呰繃 " + rule.getMaxStep());
+ return validatedChange.reject(validatedChange.getTargetKey() + " 鍗曟璋冩暣姝ラ暱涓嶈兘瓒呰繃 " + rule.getMaxStep());
}
- Date cooldownExpireTime = findCooldownExpireTime(command, now);
+ Date cooldownExpireTime = findCooldownExpireTime(validatedChange, now);
if (cooldownExpireTime != null) {
validatedChange.setCooldownExpireTime(cooldownExpireTime);
return validatedChange.reject("鐩爣浠嶅湪鍐峰嵈鏈燂紝鍐峰嵈鎴鏃堕棿: " + cooldownExpireTime);
@@ -191,86 +369,81 @@
return validatedChange.accept(dryRun ? ChangeStatus.DRY_RUN : ChangeStatus.PENDING, null);
}
- private CurrentValue readCurrentValueForValidation(AutoTuneChangeCommand command, AutoTuneRuleDefinition.Rule rule) {
+ private CurrentValue readCurrentValueForValidation(ValidatedChange validatedChange, AutoTuneRuleDefinition.Rule rule) {
AutoTuneTargetType targetType = rule.getTargetType();
- Integer targetId = parseTargetId(command.getTargetId(), targetType);
+ Integer targetId = parseTargetId(validatedChange.getTargetId(), targetType);
if (!AutoTuneTargetType.SYS_CONFIG.equals(targetType) && targetId == null) {
return CurrentValue.rejected("targetId 蹇呴』涓烘暣鏁�");
}
if (AutoTuneTargetType.SYS_CONFIG.equals(targetType)) {
- Config config = configService.getOne(new QueryWrapper<Config>().eq("code", command.getTargetKey()).last("limit 1"));
+ Config config = configService.getOne(new QueryWrapper<Config>().eq("code", validatedChange.getTargetKey()).last("limit 1"));
if (config == null) {
- return CurrentValue.rejected("杩愯鍙傛暟涓嶅瓨鍦�: " + command.getTargetKey());
+ return CurrentValue.rejected("杩愯鍙傛暟涓嶅瓨鍦�: " + validatedChange.getTargetKey());
}
- return numericCurrentValue(config.getValue(), false, command.getTargetKey());
+ return numericCurrentValue(config.getValue(), validatedChange.getTargetKey());
}
if (AutoTuneTargetType.STATION.equals(targetType)) {
BasStation station = basStationService.getById(targetId);
if (station == null) {
- return CurrentValue.rejected("绔欑偣涓嶅瓨鍦�: " + command.getTargetId());
+ return CurrentValue.rejected("绔欑偣涓嶅瓨鍦�: " + validatedChange.getTargetId());
}
- return numericCurrentValue(toText(station.getOutTaskLimit()), true, command.getTargetKey());
+ return stationOutTaskLimitCurrentValue(station.getOutTaskLimit(), validatedChange.getTargetKey());
}
if (AutoTuneTargetType.CRN.equals(targetType)) {
BasCrnp crnp = basCrnpService.getById(targetId);
if (crnp == null) {
- return CurrentValue.rejected("鍫嗗灈鏈轰笉瀛樺湪: " + command.getTargetId());
+ return CurrentValue.rejected("鍫嗗灈鏈轰笉瀛樺湪: " + validatedChange.getTargetId());
}
- Integer value = "maxOutTask".equals(command.getTargetKey()) ? crnp.getMaxOutTask() : crnp.getMaxInTask();
- return numericCurrentValue(toText(value), false, command.getTargetKey());
+ Integer value = "maxOutTask".equals(validatedChange.getTargetKey()) ? crnp.getMaxOutTask() : crnp.getMaxInTask();
+ return numericCurrentValue(toText(value), validatedChange.getTargetKey());
}
BasDualCrnp dualCrnp = basDualCrnpService.getById(targetId);
if (dualCrnp == null) {
- return CurrentValue.rejected("鍙屽伐浣嶅爢鍨涙満涓嶅瓨鍦�: " + command.getTargetId());
+ return CurrentValue.rejected("鍙屽伐浣嶅爢鍨涙満涓嶅瓨鍦�: " + validatedChange.getTargetId());
}
- Integer value = "maxOutTask".equals(command.getTargetKey()) ? dualCrnp.getMaxOutTask() : dualCrnp.getMaxInTask();
- return numericCurrentValue(toText(value), false, command.getTargetKey());
+ Integer value = "maxOutTask".equals(validatedChange.getTargetKey()) ? dualCrnp.getMaxOutTask() : dualCrnp.getMaxInTask();
+ return numericCurrentValue(toText(value), validatedChange.getTargetKey());
}
- private CurrentValue numericCurrentValue(String oldValue, boolean nullOrNegativeAsZero, String targetKey) {
+ private CurrentValue stationOutTaskLimitCurrentValue(Integer outTaskLimit, String targetKey) {
+ if (outTaskLimit == null || outTaskLimit < 0) {
+ return CurrentValue.rejected(targetKey + " 褰撳墠涓轰笉闄愬埗锛岄渶瑕佷汉宸ュ厛鍒濆鍖栦负鏈夐檺鍊煎悗鎵嶈兘鑷姩璋冨弬");
+ }
+ return numericCurrentValue(toText(outTaskLimit), targetKey);
+ }
+
+ private CurrentValue numericCurrentValue(String oldValue, String targetKey) {
if (oldValue == null || oldValue.trim().isEmpty()) {
- if (nullOrNegativeAsZero) {
- return CurrentValue.accepted(null, 0);
- }
return CurrentValue.rejected(targetKey + " 褰撳墠鍊间负绌猴紝鏃犳硶璁$畻姝ラ暱");
}
try {
Integer parsedValue = Integer.valueOf(oldValue.trim());
- if (nullOrNegativeAsZero && parsedValue < 0) {
- return CurrentValue.accepted(oldValue, 0);
- }
return CurrentValue.accepted(oldValue, parsedValue);
} catch (Exception exception) {
return CurrentValue.rejected(targetKey + " 褰撳墠鍊间笉鏄暣鏁帮紝鏃犳硶璁$畻姝ラ暱");
}
}
- private Integer resolveMaxValue(AutoTuneChangeCommand command,
+ private Integer resolveMaxValue(ValidatedChange validatedChange,
AutoTuneRuleDefinition.Rule rule,
Integer requestedValue) {
if (!rule.isDynamicMaxValue()) {
return rule.getMaxValue();
}
- Integer targetId = parseTargetId(command.getTargetId(), rule.getTargetType());
- StationFlowCapacity capacity = stationFlowCapacityService.getOne(
- new QueryWrapper<StationFlowCapacity>()
- .eq("station_id", targetId)
- .eq("direction_code", DIRECTION_OUT)
- .last("limit 1")
- );
- if (capacity == null || capacity.getBufferCapacity() == null) {
+ Integer targetId = parseTargetId(validatedChange.getTargetId(), rule.getTargetType());
+ BasStation station = basStationService.getById(targetId);
+ if (station == null || station.getOutBufferCapacity() == null) {
return requestedValue == 0 ? 0 : null;
}
- return Math.max(0, capacity.getBufferCapacity());
+ return Math.max(0, station.getOutBufferCapacity());
}
- private Date findCooldownExpireTime(AutoTuneChangeCommand command, Date now) {
- String targetId = normalizeTargetId(command.getTargetType(), command.getTargetId());
+ private Date findCooldownExpireTime(ValidatedChange validatedChange, Date now) {
List<AiAutoTuneChange> recentChanges = aiAutoTuneChangeService.list(
new QueryWrapper<AiAutoTuneChange>()
- .eq("target_type", command.getTargetType())
- .eq("target_id", targetId)
- .eq("target_key", command.getTargetKey())
+ .eq("target_type", validatedChange.getTargetType())
+ .eq("target_id", validatedChange.getTargetId())
+ .eq("target_key", validatedChange.getTargetKey())
.eq("result_status", ChangeStatus.SUCCESS.getCode())
.gt("cooldown_expire_time", now)
.orderByDesc("create_time")
@@ -287,68 +460,331 @@
return cooldownExpireTime;
}
- private void applyValidatedChanges(List<ValidatedChange> validatedChanges) {
+ private ApplyPersistenceResult persistApplyResultInTransaction(AiAutoTuneJob job,
+ AutoTuneApplyRequest request,
+ List<ValidatedChange> validatedChanges,
+ boolean dryRun,
+ Date now,
+ boolean writeTargets) {
+ TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
+ return transactionTemplate.execute(status -> persistApplyResult(
+ job,
+ request,
+ validatedChanges,
+ dryRun,
+ now,
+ writeTargets
+ ));
+ }
+
+ private ApplyPersistenceResult persistApplyResult(AiAutoTuneJob job,
+ AutoTuneApplyRequest request,
+ List<ValidatedChange> validatedChanges,
+ boolean dryRun,
+ Date now,
+ boolean writeTargets) {
+ saveJob(job);
+ boolean refreshConfigCache = false;
+ if (writeTargets) {
+ refreshConfigCache = applyValidatedChanges(validatedChanges);
+ }
+ List<AiAutoTuneChange> auditChanges = buildAuditChanges(job.getId(), validatedChanges, now);
+ saveAuditChanges(auditChanges);
+ finishJob(job, request, auditChanges, dryRun, now);
+ updateJob(job);
+ return new ApplyPersistenceResult(auditChanges, refreshConfigCache);
+ }
+
+ private void saveJob(AiAutoTuneJob job) {
+ if (!aiAutoTuneJobService.save(job)) {
+ throw new IllegalStateException("淇濆瓨璋冨弬浠诲姟澶辫触");
+ }
+ }
+
+ private boolean applyValidatedChanges(List<ValidatedChange> validatedChanges) {
boolean refreshConfigCache = false;
for (ValidatedChange validatedChange : validatedChanges) {
if (ChangeStatus.NO_CHANGE.equals(validatedChange.getStatus())) {
continue;
}
- AutoTuneChangeCommand command = validatedChange.getCommand();
- writeValue(command.getTargetType(), command.getTargetId(), command.getTargetKey(), validatedChange.getRequestedValue());
+ writeValue(
+ validatedChange.getTargetType(),
+ validatedChange.getTargetId(),
+ validatedChange.getTargetKey(),
+ validatedChange.getRequestedValue()
+ );
validatedChange.accept(ChangeStatus.SUCCESS, null);
validatedChange.setAppliedValue(validatedChange.getRequestedValue());
- if (AutoTuneTargetType.SYS_CONFIG.getCode().equals(command.getTargetType())) {
+ if (AutoTuneTargetType.SYS_CONFIG.getCode().equals(validatedChange.getTargetType())) {
refreshConfigCache = true;
}
}
- if (refreshConfigCache) {
+ return refreshConfigCache;
+ }
+
+ private void saveAuditChanges(List<AiAutoTuneChange> auditChanges) {
+ if (auditChanges.isEmpty()) {
+ return;
+ }
+ if (!aiAutoTuneChangeService.saveBatch(auditChanges)) {
+ throw new IllegalStateException("淇濆瓨璋冨弬瀹¤澶辫触");
+ }
+ }
+
+ private void updateJob(AiAutoTuneJob job) {
+ if (!aiAutoTuneJobService.updateById(job)) {
+ throw new IllegalStateException("鏇存柊璋冨弬浠诲姟鐘舵�佸け璐�");
+ }
+ }
+
+ private void refreshSystemConfigCacheSafely(ApplyPersistenceResult persistenceResult) {
+ if (persistenceResult != null && persistenceResult.isRefreshConfigCache()) {
+ refreshSystemConfigCacheSafely("apply");
+ }
+ }
+
+ private void persistNoRollbackSourceJobInTransaction(AiAutoTuneJob rollbackJob, Date now) {
+ TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
+ transactionTemplate.executeWithoutResult(status -> {
+ saveJob(rollbackJob);
+ rollbackJob.setStatus(AutoTuneJobStatus.REJECTED.getCode());
+ rollbackJob.setFinishTime(now);
+ rollbackJob.setRejectCount(0);
+ rollbackJob.setSuccessCount(0);
+ rollbackJob.setSummary("鏈壘鍒板彲鍥炴粴鐨勬垚鍔熻皟鍙傝褰�");
+ rollbackJob.setErrorMessage("鏈壘鍒板彲鍥炴粴鐨勬垚鍔熻皟鍙傝褰�");
+ updateJob(rollbackJob);
+ });
+ }
+
+ private RollbackPersistenceResult persistRollbackResultInTransaction(AiAutoTuneJob rollbackJob,
+ List<AiAutoTuneChange> sourceChanges,
+ Date now) {
+ TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
+ return transactionTemplate.execute(status -> {
+ saveJob(rollbackJob);
+ RollbackPersistenceResult rollbackResult = rollbackChanges(rollbackJob.getId(), sourceChanges, now);
+ saveAuditChanges(rollbackResult.getRollbackChanges());
+ finishRollbackJob(rollbackJob, rollbackResult.getRollbackChanges(), now);
+ updateJob(rollbackJob);
+ return rollbackResult;
+ });
+ }
+
+ private RollbackPersistenceResult persistFailedRollbackResultInTransaction(AiAutoTuneJob rollbackJob,
+ List<AiAutoTuneChange> sourceChanges,
+ RuntimeException exception,
+ Date now) {
+ TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
+ return transactionTemplate.execute(status -> {
+ saveJob(rollbackJob);
+ List<AiAutoTuneChange> rollbackChanges = buildFailedRollbackChanges(
+ rollbackJob.getId(),
+ sourceChanges,
+ exception,
+ now
+ );
+ saveAuditChanges(rollbackChanges);
+ finishRollbackJob(rollbackJob, rollbackChanges, now);
+ updateJob(rollbackJob);
+ return new RollbackPersistenceResult(rollbackChanges, false);
+ });
+ }
+
+ private RollbackPersistenceResult persistRollbackLockFailureInTransaction(AiAutoTuneJob rollbackJob, Date now) {
+ TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
+ return transactionTemplate.execute(status -> {
+ saveJob(rollbackJob);
+ List<AiAutoTuneChange> rollbackChanges = buildRollbackLockFailureChanges(rollbackJob.getId(), now);
+ saveAuditChanges(rollbackChanges);
+ finishRollbackJob(rollbackJob, rollbackChanges, now);
+ updateJob(rollbackJob);
+ return new RollbackPersistenceResult(rollbackChanges, false);
+ });
+ }
+
+ private ApplyPersistenceResult persistAnalysisOnlyApplyRejectionInTransaction(AiAutoTuneJob job,
+ AutoTuneApplyRequest request,
+ Date now) {
+ TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
+ return transactionTemplate.execute(status -> {
+ saveJob(job);
+ List<AiAutoTuneChange> auditChanges = buildAnalysisOnlyApplyChanges(job.getId(), request, now);
+ saveAuditChanges(auditChanges);
+ finishAnalysisOnlyRejectedJob(job, auditChanges, now);
+ updateJob(job);
+ return new ApplyPersistenceResult(auditChanges, false);
+ });
+ }
+
+ private RollbackPersistenceResult persistAnalysisOnlyRollbackRejectionInTransaction(AiAutoTuneJob rollbackJob,
+ Date now) {
+ TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
+ return transactionTemplate.execute(status -> {
+ saveJob(rollbackJob);
+ List<AiAutoTuneChange> rollbackChanges = buildAnalysisOnlyRollbackChanges(rollbackJob.getId(), now);
+ saveAuditChanges(rollbackChanges);
+ finishAnalysisOnlyRejectedJob(rollbackJob, rollbackChanges, now);
+ updateJob(rollbackJob);
+ return new RollbackPersistenceResult(rollbackChanges, false);
+ });
+ }
+
+ private RollbackPersistenceResult rollbackChanges(Long rollbackJobId, List<AiAutoTuneChange> sourceChanges, Date now) {
+ List<AiAutoTuneChange> rollbackChanges = new ArrayList<>();
+ boolean refreshConfigCache = false;
+ for (AiAutoTuneChange sourceChange : sourceChanges) {
+ AiAutoTuneChange rollbackChange = buildRollbackChange(rollbackJobId, sourceChange, now);
+ String currentValue = readCurrentValue(
+ sourceChange.getTargetType(),
+ sourceChange.getTargetId(),
+ sourceChange.getTargetKey()
+ );
+ rollbackChange.setOldValue(currentValue);
+ writeValue(sourceChange.getTargetType(), sourceChange.getTargetId(), sourceChange.getTargetKey(), sourceChange.getOldValue());
+ if (AutoTuneTargetType.SYS_CONFIG.getCode().equals(sourceChange.getTargetType())) {
+ refreshConfigCache = true;
+ }
+ rollbackChange.setAppliedValue(sourceChange.getOldValue());
+ rollbackChange.setResultStatus(ChangeStatus.SUCCESS.getCode());
+ rollbackChanges.add(rollbackChange);
+ }
+ return new RollbackPersistenceResult(rollbackChanges, refreshConfigCache);
+ }
+
+ private List<AiAutoTuneChange> buildRollbackLockFailureChanges(Long rollbackJobId, Date now) {
+ AiAutoTuneChange rollbackChange = new AiAutoTuneChange();
+ rollbackChange.setJobId(rollbackJobId);
+ rollbackChange.setTargetType(AutoTuneTriggerType.ROLLBACK.getCode());
+ rollbackChange.setTargetId("");
+ rollbackChange.setTargetKey("latest_successful_job");
+ rollbackChange.setResultStatus(ChangeStatus.FAILED.getCode());
+ rollbackChange.setRejectReason(APPLY_LOCK_BUSY_REASON);
+ rollbackChange.setCreateTime(now);
+ return List.of(rollbackChange);
+ }
+
+ private List<AiAutoTuneChange> buildAnalysisOnlyApplyChanges(Long jobId,
+ AutoTuneApplyRequest request,
+ Date now) {
+ List<AiAutoTuneChange> changes = new ArrayList<>();
+ List<AutoTuneChangeCommand> commands = request == null ? null : request.getChanges();
+ if (commands == null || commands.isEmpty()) {
+ changes.add(buildAnalysisOnlyChange(jobId, "analysis_only", "", "apply", null, now));
+ return changes;
+ }
+ for (AutoTuneChangeCommand command : commands) {
+ changes.add(buildAnalysisOnlyChange(
+ jobId,
+ normalizeText(command == null ? null : command.getTargetType()),
+ normalizeText(command == null ? null : command.getTargetId()),
+ normalizeText(command == null ? null : command.getTargetKey()),
+ command == null ? null : command.getNewValue(),
+ now
+ ));
+ }
+ return changes;
+ }
+
+ private List<AiAutoTuneChange> buildAnalysisOnlyRollbackChanges(Long jobId, Date now) {
+ AiAutoTuneChange rollbackChange = buildAnalysisOnlyChange(
+ jobId,
+ "analysis_only",
+ "",
+ "rollback",
+ null,
+ now
+ );
+ return List.of(rollbackChange);
+ }
+
+ private AiAutoTuneChange buildAnalysisOnlyChange(Long jobId,
+ String targetType,
+ String targetId,
+ String targetKey,
+ String requestedValue,
+ Date now) {
+ AiAutoTuneChange change = new AiAutoTuneChange();
+ change.setJobId(jobId);
+ change.setTargetType(targetType);
+ change.setTargetId(targetId);
+ change.setTargetKey(targetKey);
+ change.setRequestedValue(requestedValue);
+ change.setResultStatus(ChangeStatus.REJECTED.getCode());
+ change.setRejectReason(ANALYSIS_ONLY_REJECT_REASON);
+ change.setCreateTime(now);
+ return change;
+ }
+
+ private void refreshRollbackConfigCacheSafely(RollbackPersistenceResult persistenceResult) {
+ if (persistenceResult != null && persistenceResult.isRefreshConfigCache()) {
+ refreshSystemConfigCacheSafely("rollback");
+ }
+ }
+
+ private void refreshSystemConfigCacheSafely(String scene) {
+ try {
configService.refreshSystemConfigCache();
+ } catch (RuntimeException exception) {
+ LOGGER.warn("AI鑷姩璋冨弬{}宸叉彁浜わ紝浣嗗埛鏂扮郴缁熼厤缃紦瀛樺け璐�", scene, exception);
}
}
private void writeValue(String targetType, String targetId, String targetKey, String value) {
- AutoTuneTargetType parsedTargetType = AutoTuneTargetType.fromCode(targetType);
+ String normalizedTargetType = normalizeText(targetType);
+ String normalizedTargetKey = normalizeText(targetKey);
+ String normalizedTargetId = normalizeTargetId(normalizedTargetType, targetId);
+ AutoTuneTargetType parsedTargetType = AutoTuneTargetType.fromCode(normalizedTargetType);
+ if (parsedTargetType == null) {
+ throw new IllegalArgumentException("涓嶆敮鎸佺殑璋冨弬鐩爣: " + normalizedTargetType + "/" + normalizedTargetKey);
+ }
if (AutoTuneTargetType.SYS_CONFIG.equals(parsedTargetType)) {
- if (!configService.saveConfigValue(targetKey, value)) {
- throw new IllegalStateException("淇濆瓨杩愯鍙傛暟澶辫触: " + targetKey);
+ if (!configService.saveConfigValue(normalizedTargetKey, value)) {
+ throw new IllegalStateException("淇濆瓨杩愯鍙傛暟澶辫触: " + normalizedTargetKey);
}
return;
}
- Integer parsedTargetId = parseTargetId(targetId, parsedTargetType);
+ Integer parsedTargetId = parseTargetId(normalizedTargetId, parsedTargetType);
Integer intValue = value == null ? null : Integer.valueOf(value);
if (AutoTuneTargetType.STATION.equals(parsedTargetType)) {
boolean updated = basStationService.update(new UpdateWrapper<BasStation>()
.eq("station_id", parsedTargetId)
.set("out_task_limit", intValue));
if (!updated) {
- throw new IllegalStateException("淇濆瓨绔欑偣鍙傛暟澶辫触: " + targetId + "/" + targetKey);
+ throw new IllegalStateException("淇濆瓨绔欑偣鍙傛暟澶辫触: " + normalizedTargetId + "/" + normalizedTargetKey);
}
return;
}
if (AutoTuneTargetType.CRN.equals(parsedTargetType)) {
- String column = "maxOutTask".equals(targetKey) ? "max_out_task" : "max_in_task";
+ String column = "maxOutTask".equals(normalizedTargetKey) ? "max_out_task" : "max_in_task";
boolean updated = basCrnpService.update(new UpdateWrapper<BasCrnp>()
.eq("crn_no", parsedTargetId)
.set(column, intValue));
if (!updated) {
- throw new IllegalStateException("淇濆瓨鍫嗗灈鏈哄弬鏁板け璐�: " + targetId + "/" + targetKey);
+ throw new IllegalStateException("淇濆瓨鍫嗗灈鏈哄弬鏁板け璐�: " + normalizedTargetId + "/" + normalizedTargetKey);
}
return;
}
- String column = "maxOutTask".equals(targetKey) ? "max_out_task" : "max_in_task";
+ String column = "maxOutTask".equals(normalizedTargetKey) ? "max_out_task" : "max_in_task";
boolean updated = basDualCrnpService.update(new UpdateWrapper<BasDualCrnp>()
.eq("crn_no", parsedTargetId)
.set(column, intValue));
if (!updated) {
- throw new IllegalStateException("淇濆瓨鍙屽伐浣嶅爢鍨涙満鍙傛暟澶辫触: " + targetId + "/" + targetKey);
+ throw new IllegalStateException("淇濆瓨鍙屽伐浣嶅爢鍨涙満鍙傛暟澶辫触: " + normalizedTargetId + "/" + normalizedTargetKey);
}
}
private String readCurrentValue(String targetType, String targetId, String targetKey) {
- AutoTuneTargetType parsedTargetType = AutoTuneTargetType.fromCode(targetType);
- Integer parsedTargetId = parseTargetId(targetId, parsedTargetType);
+ String normalizedTargetType = normalizeText(targetType);
+ String normalizedTargetKey = normalizeText(targetKey);
+ String normalizedTargetId = normalizeTargetId(normalizedTargetType, targetId);
+ AutoTuneTargetType parsedTargetType = AutoTuneTargetType.fromCode(normalizedTargetType);
+ if (parsedTargetType == null) {
+ throw new IllegalArgumentException("涓嶆敮鎸佺殑璋冨弬鐩爣: " + normalizedTargetType + "/" + normalizedTargetKey);
+ }
+ Integer parsedTargetId = parseTargetId(normalizedTargetId, parsedTargetType);
if (AutoTuneTargetType.SYS_CONFIG.equals(parsedTargetType)) {
- Config config = configService.getOne(new QueryWrapper<Config>().eq("code", targetKey).last("limit 1"));
+ Config config = configService.getOne(new QueryWrapper<Config>().eq("code", normalizedTargetKey).last("limit 1"));
return config == null ? null : config.getValue();
}
if (AutoTuneTargetType.STATION.equals(parsedTargetType)) {
@@ -360,13 +796,13 @@
if (crnp == null) {
return null;
}
- return toText("maxOutTask".equals(targetKey) ? crnp.getMaxOutTask() : crnp.getMaxInTask());
+ return toText("maxOutTask".equals(normalizedTargetKey) ? crnp.getMaxOutTask() : crnp.getMaxInTask());
}
BasDualCrnp dualCrnp = basDualCrnpService.getById(parsedTargetId);
if (dualCrnp == null) {
return null;
}
- return toText("maxOutTask".equals(targetKey) ? dualCrnp.getMaxOutTask() : dualCrnp.getMaxInTask());
+ return toText("maxOutTask".equals(normalizedTargetKey) ? dualCrnp.getMaxOutTask() : dualCrnp.getMaxInTask());
}
private AiAutoTuneJob createJob(AutoTuneApplyRequest request, boolean dryRun, Date now) {
@@ -374,7 +810,7 @@
job.setTriggerType(AutoTuneTriggerType.normalize(request.getTriggerType()));
job.setStatus(AutoTuneJobStatus.RUNNING.getCode());
job.setStartTime(now);
- job.setHasActiveTasks(0);
+ job.setHasActiveTasks(resolveHasActiveTasksForAudit());
job.setPromptSceneCode(PROMPT_SCENE_CODE);
job.setSummary(dryRun ? "AI鑷姩璋冨弬 dry-run: " + safeReason(request.getReason()) : safeReason(request.getReason()));
job.setIntervalBefore(readIntervalMinutes());
@@ -393,7 +829,7 @@
job.setTriggerType(AutoTuneTriggerType.ROLLBACK.getCode());
job.setStatus(AutoTuneJobStatus.RUNNING.getCode());
job.setStartTime(now);
- job.setHasActiveTasks(0);
+ job.setHasActiveTasks(resolveHasActiveTasksForAudit());
job.setPromptSceneCode(PROMPT_SCENE_CODE);
job.setSummary(safeReason(reason));
job.setIntervalBefore(readIntervalMinutes());
@@ -405,6 +841,21 @@
job.setTotalTokens(0);
job.setCreateTime(now);
return job;
+ }
+
+ private int resolveHasActiveTasksForAudit() {
+ if (wrkMastService == null) {
+ LOGGER.warn("AI鑷姩璋冨弬瀹¤鏃犳硶鑾峰彇 WrkMastService锛宧asActiveTasks 鎸� 0 璁板綍");
+ return 0;
+ }
+ try {
+ QueryWrapper<WrkMast> queryWrapper = new QueryWrapper<>();
+ queryWrapper.and(wrapper -> wrapper.notIn("wrk_sts", FINAL_WRK_STS_LIST).or().isNull("wrk_sts"));
+ return wrkMastService.count(queryWrapper) > 0 ? 1 : 0;
+ } catch (RuntimeException exception) {
+ LOGGER.warn("AI鑷姩璋冨弬瀹¤鏌ヨ鏈畬鎴愪换鍔″け璐ワ紝hasActiveTasks 鎸� 0 璁板綍", exception);
+ return 0;
+ }
}
private void finishJob(AiAutoTuneJob job,
@@ -425,6 +876,17 @@
}
}
+ private void finishAnalysisOnlyRejectedJob(AiAutoTuneJob job, List<AiAutoTuneChange> changes, Date now) {
+ int rejectCount = Math.max(1, countRejected(changes));
+ job.setFinishTime(now);
+ job.setSuccessCount(0);
+ job.setRejectCount(rejectCount);
+ job.setIntervalAfter(readIntervalMinutes());
+ job.setStatus(AutoTuneJobStatus.REJECTED.getCode());
+ job.setSummary(ANALYSIS_ONLY_REJECT_REASON);
+ job.setErrorMessage(ANALYSIS_ONLY_REJECT_REASON);
+ }
+
private void finishRollbackJob(AiAutoTuneJob job, List<AiAutoTuneChange> changes, Date now) {
int successCount = countAccepted(changes);
int rejectCount = countRejected(changes);
@@ -432,7 +894,15 @@
job.setSuccessCount(successCount);
job.setRejectCount(rejectCount);
job.setIntervalAfter(readIntervalMinutes());
- job.setStatus(rejectCount == 0 ? AutoTuneJobStatus.SUCCESS.getCode() : AutoTuneJobStatus.PARTIAL_SUCCESS.getCode());
+ if (rejectCount == 0) {
+ job.setStatus(AutoTuneJobStatus.SUCCESS.getCode());
+ } else if (successCount == 0 && hasFailedChange(changes)) {
+ job.setStatus(AutoTuneJobStatus.FAILED.getCode());
+ } else if (successCount == 0) {
+ job.setStatus(AutoTuneJobStatus.REJECTED.getCode());
+ } else {
+ job.setStatus(AutoTuneJobStatus.PARTIAL_SUCCESS.getCode());
+ }
job.setSummary("鍥炴粴鏈�杩戜竴娆℃垚鍔熻皟鍙傦紝鎴愬姛 " + successCount + " 椤癸紝澶辫触 " + rejectCount + " 椤�");
if (rejectCount > 0) {
job.setErrorMessage(firstRejectReason(changes));
@@ -442,6 +912,9 @@
private String resolveJobStatus(List<AiAutoTuneChange> auditChanges, boolean dryRun) {
if (auditChanges.isEmpty()) {
return AutoTuneJobStatus.NO_CHANGE.getCode();
+ }
+ if (hasFailedChange(auditChanges)) {
+ return AutoTuneJobStatus.FAILED.getCode();
}
int rejectedCount = countRejected(auditChanges);
int acceptedCount = countAccepted(auditChanges);
@@ -468,13 +941,14 @@
List<AiAutoTuneChange> auditChanges = new ArrayList<>();
for (ValidatedChange validatedChange : validatedChanges) {
AiAutoTuneChange change = new AiAutoTuneChange();
- AutoTuneChangeCommand command = validatedChange.getCommand();
change.setJobId(jobId);
- change.setTargetType(command.getTargetType());
- change.setTargetId(normalizeTargetId(command.getTargetType(), command.getTargetId()));
- change.setTargetKey(command.getTargetKey());
+ change.setTargetType(validatedChange.getTargetType());
+ change.setTargetId(validatedChange.getTargetId());
+ change.setTargetKey(validatedChange.getTargetKey());
change.setOldValue(validatedChange.getOldValue());
- change.setRequestedValue(validatedChange.getRequestedValue() == null ? command.getNewValue() : validatedChange.getRequestedValue());
+ change.setRequestedValue(validatedChange.getRequestedValue() == null
+ ? validatedChange.getRawRequestedValue()
+ : validatedChange.getRequestedValue());
change.setAppliedValue(validatedChange.getAppliedValue());
change.setResultStatus(validatedChange.getStatus().getCode());
change.setRejectReason(validatedChange.getRejectReason());
@@ -497,17 +971,26 @@
}
private List<AiAutoTuneChange> findLatestSuccessfulChanges() {
- List<AiAutoTuneJob> jobs = aiAutoTuneJobService.list(
- new QueryWrapper<AiAutoTuneJob>()
- .eq("status", AutoTuneJobStatus.SUCCESS.getCode())
- .ne("trigger_type", AutoTuneTriggerType.ROLLBACK.getCode())
- .orderByDesc("finish_time")
- .last("limit 20")
+ List<AiAutoTuneChange> successfulChanges = aiAutoTuneChangeService.list(
+ new QueryWrapper<AiAutoTuneChange>()
+ .eq("result_status", ChangeStatus.SUCCESS.getCode())
+ .orderByDesc("create_time")
+ .orderByDesc("id")
);
- if (jobs == null || jobs.isEmpty()) {
+ if (successfulChanges == null || successfulChanges.isEmpty()) {
return new ArrayList<>();
}
- for (AiAutoTuneJob job : jobs) {
+ Set<Long> checkedJobIds = new HashSet<>();
+ for (AiAutoTuneChange successfulChange : successfulChanges) {
+ Long jobId = successfulChange.getJobId();
+ if (jobId == null || checkedJobIds.contains(jobId)) {
+ continue;
+ }
+ checkedJobIds.add(jobId);
+ AiAutoTuneJob job = aiAutoTuneJobService.getById(jobId);
+ if (!isRollbackCandidate(job)) {
+ continue;
+ }
List<AiAutoTuneChange> changes = aiAutoTuneChangeService.list(
new QueryWrapper<AiAutoTuneChange>()
.eq("job_id", job.getId())
@@ -521,11 +1004,26 @@
return new ArrayList<>();
}
- private AutoTuneApplyResult buildResult(AiAutoTuneJob job, List<AiAutoTuneChange> changes, boolean dryRun) {
+ private boolean isRollbackCandidate(AiAutoTuneJob job) {
+ if (job == null) {
+ return false;
+ }
+ if (!AutoTuneJobStatus.SUCCESS.getCode().equals(job.getStatus())) {
+ return false;
+ }
+ return !AutoTuneTriggerType.ROLLBACK.getCode().equals(job.getTriggerType());
+ }
+
+ private AutoTuneApplyResult buildResult(AiAutoTuneJob job,
+ List<AiAutoTuneChange> changes,
+ boolean dryRun,
+ AutoTuneControlModeSnapshot controlMode) {
AutoTuneApplyResult result = new AutoTuneApplyResult();
result.setDryRun(dryRun);
result.setSuccess(AutoTuneJobStatus.SUCCESS.getCode().equals(job.getStatus())
|| AutoTuneJobStatus.NO_CHANGE.getCode().equals(job.getStatus()));
+ result.setAnalysisOnly(isAnalysisOnly(controlMode));
+ result.setNoApply(false);
result.setJobId(job.getId());
result.setSummary(job.getSummary());
result.setSuccessCount(job.getSuccessCount());
@@ -544,6 +1042,31 @@
}
validatedChange.reject("鍚屾壒娆″瓨鍦ㄨ鎷掔粷鍙樻洿锛屾湭鎵ц鍐欏叆");
}
+ }
+
+ private void markWriteFailure(List<ValidatedChange> validatedChanges, RuntimeException exception) {
+ String reason = exception.getMessage() == null ? "鐩爣鍐欏叆澶辫触" : exception.getMessage();
+ for (ValidatedChange validatedChange : validatedChanges) {
+ if (ChangeStatus.NO_CHANGE.equals(validatedChange.getStatus())) {
+ continue;
+ }
+ validatedChange.fail(reason);
+ }
+ }
+
+ private List<AiAutoTuneChange> buildFailedRollbackChanges(Long rollbackJobId,
+ List<AiAutoTuneChange> sourceChanges,
+ RuntimeException exception,
+ Date now) {
+ String reason = exception.getMessage() == null ? "鍥炴粴鍐欏叆澶辫触" : exception.getMessage();
+ List<AiAutoTuneChange> rollbackChanges = new ArrayList<>();
+ for (AiAutoTuneChange sourceChange : sourceChanges) {
+ AiAutoTuneChange rollbackChange = buildRollbackChange(rollbackJobId, sourceChange, now);
+ rollbackChange.setResultStatus(ChangeStatus.FAILED.getCode());
+ rollbackChange.setRejectReason(reason);
+ rollbackChanges.add(rollbackChange);
+ }
+ return rollbackChanges;
}
private boolean hasRejectedChange(List<ValidatedChange> validatedChanges) {
@@ -580,12 +1103,16 @@
}
}
- private String normalizeTargetId(String targetType, String targetId) {
+ private static String normalizeTargetId(String targetType, String targetId) {
AutoTuneTargetType parsedTargetType = AutoTuneTargetType.fromCode(targetType);
if (AutoTuneTargetType.SYS_CONFIG.equals(parsedTargetType)) {
return "";
}
- return targetId == null ? "" : targetId.trim();
+ return normalizeText(targetId);
+ }
+
+ private static String normalizeText(String value) {
+ return value == null ? "" : value.trim();
}
private int readIntervalMinutes() {
@@ -598,6 +1125,14 @@
} catch (Exception exception) {
return 0;
}
+ }
+
+ private AutoTuneControlModeSnapshot currentControlModeSnapshot() {
+ return autoTuneControlModeService.currentMode();
+ }
+
+ private boolean isAnalysisOnly(AutoTuneControlModeSnapshot controlMode) {
+ return controlMode == null || Boolean.TRUE.equals(controlMode.getAnalysisOnly());
}
private String toText(Integer value) {
@@ -636,6 +1171,15 @@
return count;
}
+ private boolean hasFailedChange(List<AiAutoTuneChange> changes) {
+ for (AiAutoTuneChange change : changes) {
+ if (ChangeStatus.FAILED.getCode().equals(change.getResultStatus())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private String firstRejectReason(List<AiAutoTuneChange> changes) {
for (AiAutoTuneChange change : changes) {
if (change.getRejectReason() != null && !change.getRejectReason().trim().isEmpty()) {
@@ -645,8 +1189,48 @@
return null;
}
+ private static class ApplyPersistenceResult {
+ private final List<AiAutoTuneChange> auditChanges;
+ private final boolean refreshConfigCache;
+
+ private ApplyPersistenceResult(List<AiAutoTuneChange> auditChanges, boolean refreshConfigCache) {
+ this.auditChanges = auditChanges == null ? new ArrayList<>() : auditChanges;
+ this.refreshConfigCache = refreshConfigCache;
+ }
+
+ public List<AiAutoTuneChange> getAuditChanges() {
+ return auditChanges;
+ }
+
+ public boolean isRefreshConfigCache() {
+ return refreshConfigCache;
+ }
+ }
+
+ private static class RollbackPersistenceResult {
+ private final List<AiAutoTuneChange> rollbackChanges;
+ private final boolean refreshConfigCache;
+
+ private RollbackPersistenceResult(List<AiAutoTuneChange> rollbackChanges, boolean refreshConfigCache) {
+ this.rollbackChanges = rollbackChanges == null ? new ArrayList<>() : rollbackChanges;
+ this.refreshConfigCache = refreshConfigCache;
+ }
+
+ public List<AiAutoTuneChange> getRollbackChanges() {
+ return rollbackChanges;
+ }
+
+ public boolean isRefreshConfigCache() {
+ return refreshConfigCache;
+ }
+ }
+
private static class ValidatedChange {
private final AutoTuneChangeCommand command;
+ private final String targetType;
+ private final String targetId;
+ private final String targetKey;
+ private final String rawRequestedValue;
private AutoTuneRuleDefinition.Rule rule;
private String oldValue;
private String requestedValue;
@@ -658,6 +1242,10 @@
private ValidatedChange(AutoTuneChangeCommand command) {
this.command = command == null ? new AutoTuneChangeCommand() : command;
+ this.targetType = normalizeText(this.command.getTargetType());
+ this.targetId = normalizeTargetId(this.targetType, this.command.getTargetId());
+ this.targetKey = normalizeText(this.command.getTargetKey());
+ this.rawRequestedValue = this.command.getNewValue();
}
private ValidatedChange reject(String reason) {
@@ -665,6 +1253,12 @@
this.rejectReason = reason;
this.appliedValue = null;
return this;
+ }
+
+ private void fail(String reason) {
+ this.status = ChangeStatus.FAILED;
+ this.rejectReason = reason;
+ this.appliedValue = null;
}
private ValidatedChange accept(ChangeStatus status, String reason) {
@@ -680,6 +1274,22 @@
return command;
}
+ public String getTargetType() {
+ return targetType;
+ }
+
+ public String getTargetId() {
+ return targetId;
+ }
+
+ public String getTargetKey() {
+ return targetKey;
+ }
+
+ public String getRawRequestedValue() {
+ return rawRequestedValue;
+ }
+
public AutoTuneRuleDefinition.Rule getRule() {
return rule;
}
--
Gitblit v1.9.1