| | |
| | | import com.zy.system.service.ConfigService; |
| | | 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.Date; |
| | | import java.util.HashSet; |
| | | import java.util.List; |
| | | import java.util.Objects; |
| | | import java.util.Set; |
| | | |
| | | @Service("autoTuneApplyService") |
| | | public class AutoTuneApplyServiceImpl implements AutoTuneApplyService { |
| | |
| | | private BasDualCrnpService basDualCrnpService; |
| | | @Autowired |
| | | private StationFlowCapacityService stationFlowCapacityService; |
| | | @Autowired(required = false) |
| | | private PlatformTransactionManager transactionManager; |
| | | |
| | | @Override |
| | | @Transactional |
| | | public AutoTuneApplyResult apply(AutoTuneApplyRequest request) { |
| | | AutoTuneApplyRequest safeRequest = request == null ? new AutoTuneApplyRequest() : request; |
| | | boolean dryRun = Boolean.TRUE.equals(safeRequest.getDryRun()); |
| | |
| | | markAcceptedChangesAsBatchRejected(validatedChanges); |
| | | } |
| | | if (!dryRun && !hasRejectedChange) { |
| | | applyValidatedChanges(validatedChanges); |
| | | try { |
| | | applyValidatedChangesInTransaction(validatedChanges); |
| | | } catch (RuntimeException exception) { |
| | | markWriteFailure(validatedChanges, exception); |
| | | } |
| | | } |
| | | |
| | | List<AiAutoTuneChange> auditChanges = buildAuditChanges(job.getId(), validatedChanges, now); |
| | |
| | | } |
| | | |
| | | @Override |
| | | @Transactional |
| | | public AutoTuneApplyResult rollbackLastSuccessfulJob(String reason) { |
| | | Date now = new Date(); |
| | | AiAutoTuneJob rollbackJob = createRollbackJob(reason, now); |
| | |
| | | } |
| | | |
| | | 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()); |
| | | } |
| | | rollbackChanges.add(rollbackChange); |
| | | } |
| | | if (refreshedConfigCache) { |
| | | configService.refreshSystemConfigCache(); |
| | | try { |
| | | rollbackChanges = rollbackChangesInTransaction(rollbackJob.getId(), sourceChanges, now); |
| | | } catch (RuntimeException exception) { |
| | | rollbackChanges = buildFailedRollbackChanges(rollbackJob.getId(), sourceChanges, exception, now); |
| | | } |
| | | aiAutoTuneChangeService.saveBatch(rollbackChanges); |
| | | finishRollbackJob(rollbackJob, rollbackChanges, now); |
| | |
| | | return cooldownExpireTime; |
| | | } |
| | | |
| | | private void applyValidatedChangesInTransaction(List<ValidatedChange> validatedChanges) { |
| | | if (transactionManager == null) { |
| | | applyValidatedChanges(validatedChanges); |
| | | return; |
| | | } |
| | | TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager); |
| | | transactionTemplate.executeWithoutResult(status -> applyValidatedChanges(validatedChanges)); |
| | | } |
| | | |
| | | private void applyValidatedChanges(List<ValidatedChange> validatedChanges) { |
| | | boolean refreshConfigCache = false; |
| | | for (ValidatedChange validatedChange : validatedChanges) { |
| | |
| | | if (refreshConfigCache) { |
| | | configService.refreshSystemConfigCache(); |
| | | } |
| | | } |
| | | |
| | | 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)); |
| | | } |
| | | |
| | | private List<AiAutoTuneChange> 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); |
| | | } |
| | | if (refreshConfigCache) { |
| | | configService.refreshSystemConfigCache(); |
| | | } |
| | | return rollbackChanges; |
| | | } |
| | | |
| | | private void writeValue(String targetType, String targetId, String targetKey, String value) { |
| | |
| | | if (auditChanges.isEmpty()) { |
| | | return AutoTuneJobStatus.NO_CHANGE.getCode(); |
| | | } |
| | | if (hasFailedChange(auditChanges)) { |
| | | return AutoTuneJobStatus.FAILED.getCode(); |
| | | } |
| | | int rejectedCount = countRejected(auditChanges); |
| | | int acceptedCount = countAccepted(auditChanges); |
| | | if (rejectedCount == auditChanges.size()) { |
| | |
| | | } |
| | | |
| | | 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()) |
| | |
| | | } |
| | | } |
| | | return new ArrayList<>(); |
| | | } |
| | | |
| | | 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) { |
| | |
| | | } |
| | | 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) { |
| | |
| | | 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()) { |
| | |
| | | return this; |
| | | } |
| | | |
| | | private void fail(String reason) { |
| | | this.status = ChangeStatus.FAILED; |
| | | this.rejectReason = reason; |
| | | this.appliedValue = null; |
| | | } |
| | | |
| | | private ValidatedChange accept(ChangeStatus status, String reason) { |
| | | this.status = status; |
| | | this.rejectReason = reason; |