From 1080e8e862fcfb9492fd3eed78c34b7ba3abfe32 Mon Sep 17 00:00:00 2001
From: Junjie <fallin.jie@qq.com>
Date: 星期一, 27 四月 2026 11:44:08 +0800
Subject: [PATCH] fix: strengthen auto tune apply transaction safety
---
src/main/java/com/zy/ai/service/impl/AutoTuneApplyServiceImpl.java | 177 ++++++++++++++++++++++++++++++++++++++---------------------
1 files changed, 114 insertions(+), 63 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 98a588a..e6a1e20 100644
--- a/src/main/java/com/zy/ai/service/impl/AutoTuneApplyServiceImpl.java
+++ b/src/main/java/com/zy/ai/service/impl/AutoTuneApplyServiceImpl.java
@@ -56,7 +56,7 @@
private BasDualCrnpService basDualCrnpService;
@Autowired
private StationFlowCapacityService stationFlowCapacityService;
- @Autowired(required = false)
+ @Autowired
private PlatformTransactionManager transactionManager;
@Override
@@ -132,31 +132,37 @@
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);
+ Integer maxValue = resolveMaxValue(validatedChange, rule, requestedValue);
if (maxValue == null) {
- return validatedChange.reject("绔欑偣 " + command.getTargetId() + " 缂哄皯 OUT 鏂瑰悜 bufferCapacity锛屾棤娉曡瘉鏄� outTaskLimit 涓婇檺");
+ return validatedChange.reject("绔欑偣 " + validatedChange.getTargetId()
+ + " 缂哄皯 OUT 鏂瑰悜 bufferCapacity锛屾棤娉曡瘉鏄� outTaskLimit 涓婇檺");
}
if (requestedValue < rule.getMinValue() || requestedValue > maxValue) {
- return validatedChange.reject(command.getTargetKey() + " 蹇呴』鍦� " + rule.getMinValue() + "~" + maxValue + " 鑼冨洿鍐�");
+ return validatedChange.reject(validatedChange.getTargetKey() + " 蹇呴』鍦� "
+ + rule.getMinValue() + "~" + maxValue + " 鑼冨洿鍐�");
}
if (Objects.equals(currentValue.getNumericValue(), requestedValue)) {
@@ -164,10 +170,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);
@@ -178,40 +184,40 @@
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(), false, 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 numericCurrentValue(toText(station.getOutTaskLimit()), true, 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), false, 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), false, validatedChange.getTargetKey());
}
private CurrentValue numericCurrentValue(String oldValue, boolean nullOrNegativeAsZero, String targetKey) {
@@ -232,13 +238,13 @@
}
}
- 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());
+ Integer targetId = parseTargetId(validatedChange.getTargetId(), rule.getTargetType());
StationFlowCapacity capacity = stationFlowCapacityService.getOne(
new QueryWrapper<StationFlowCapacity>()
.eq("station_id", targetId)
@@ -251,13 +257,12 @@
return Math.max(0, capacity.getBufferCapacity());
}
- 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")
@@ -275,10 +280,6 @@
}
private void applyValidatedChangesInTransaction(List<ValidatedChange> validatedChanges) {
- if (transactionManager == null) {
- applyValidatedChanges(validatedChanges);
- return;
- }
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
transactionTemplate.executeWithoutResult(status -> applyValidatedChanges(validatedChanges));
}
@@ -289,11 +290,15 @@
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;
}
}
@@ -305,9 +310,6 @@
private List<AiAutoTuneChange> rollbackChangesInTransaction(Long rollbackJobId,
List<AiAutoTuneChange> sourceChanges,
Date now) {
- if (transactionManager == null) {
- return rollbackChanges(rollbackJobId, sourceChanges, now);
- }
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
return transactionTemplate.execute(status -> rollbackChanges(rollbackJobId, sourceChanges, now));
}
@@ -338,48 +340,60 @@
}
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)) {
@@ -391,13 +405,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) {
@@ -463,7 +477,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));
@@ -502,13 +524,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());
@@ -658,12 +681,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() {
@@ -734,6 +761,10 @@
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;
@@ -745,6 +776,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) {
@@ -773,6 +808,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