| | |
| | | import com.zy.asrs.service.BasDualCrnpService; |
| | | import com.zy.asrs.service.BasStationService; |
| | | import com.zy.asrs.service.StationFlowCapacityService; |
| | | import com.zy.common.utils.RedisUtil; |
| | | import com.zy.core.enums.RedisKeyType; |
| | | import com.zy.system.entity.Config; |
| | | import com.zy.system.service.ConfigService; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | |
| | | 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 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 = "AI自动调参正在执行,请稍后重试"; |
| | | |
| | | @Autowired |
| | | private AiAutoTuneJobService aiAutoTuneJobService; |
| | |
| | | private StationFlowCapacityService stationFlowCapacityService; |
| | | @Autowired |
| | | private PlatformTransactionManager transactionManager; |
| | | @Autowired |
| | | private RedisUtil redisUtil; |
| | | |
| | | @Override |
| | | public AutoTuneApplyResult apply(AutoTuneApplyRequest request) { |
| | |
| | | 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); |
| | | } |
| | | if (!dryRun && !hasRejectedChange) { |
| | | try { |
| | | applyValidatedChangesInTransaction(validatedChanges); |
| | | } catch (RuntimeException exception) { |
| | | markWriteFailure(validatedChanges, exception); |
| | | } |
| | | return applyRealWithLock(safeRequest, job, now); |
| | | } |
| | | |
| | | private AutoTuneApplyResult applyDryRun(AutoTuneApplyRequest request, AiAutoTuneJob job, Date now) { |
| | | List<ValidatedChange> validatedChanges = validateChanges(request, true, now); |
| | | ApplyPersistenceResult persistenceResult = persistApplyResultInTransaction( |
| | | job, |
| | | request, |
| | | validatedChanges, |
| | | true, |
| | | now, |
| | | false |
| | | ); |
| | | return buildResult(job, persistenceResult.getAuditChanges(), true); |
| | | } |
| | | |
| | | private AutoTuneApplyResult applyRealWithLock(AutoTuneApplyRequest request, AiAutoTuneJob job, Date now) { |
| | | if (request.getChanges() == null || request.getChanges().isEmpty()) { |
| | | ApplyPersistenceResult persistenceResult = persistApplyResultInTransaction( |
| | | job, |
| | | request, |
| | | new ArrayList<>(), |
| | | false, |
| | | now, |
| | | false |
| | | ); |
| | | return buildResult(job, persistenceResult.getAuditChanges(), false); |
| | | } |
| | | |
| | | 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 rejectRealApplyForBusyLock(request, job, now); |
| | | } |
| | | 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); |
| | | } |
| | | |
| | | try { |
| | | ApplyPersistenceResult persistenceResult = persistApplyResultInTransaction( |
| | | job, |
| | | request, |
| | | validatedChanges, |
| | | false, |
| | | now, |
| | | true |
| | | ); |
| | | refreshSystemConfigCacheIfNeeded(persistenceResult); |
| | | return buildResult(job, persistenceResult.getAuditChanges(), false); |
| | | } catch (RuntimeException exception) { |
| | | markWriteFailure(validatedChanges, exception); |
| | | ApplyPersistenceResult persistenceResult = persistApplyResultInTransaction( |
| | | job, |
| | | request, |
| | | validatedChanges, |
| | | false, |
| | | now, |
| | | false |
| | | ); |
| | | return buildResult(job, persistenceResult.getAuditChanges(), false); |
| | | } |
| | | } finally { |
| | | redisUtil.compareAndDelete(lockKey, lockToken); |
| | | } |
| | | } |
| | | |
| | | private AutoTuneApplyResult rejectRealApplyForBusyLock(AutoTuneApplyRequest request, AiAutoTuneJob job, Date now) { |
| | | List<ValidatedChange> validatedChanges = buildLockBusyChanges(request); |
| | | ApplyPersistenceResult persistenceResult = persistApplyResultInTransaction( |
| | | job, |
| | | request, |
| | | validatedChanges, |
| | | false, |
| | | now, |
| | | false |
| | | ); |
| | | return buildResult(job, persistenceResult.getAuditChanges(), false); |
| | | } |
| | | |
| | | 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 |
| | |
| | | return cooldownExpireTime; |
| | | } |
| | | |
| | | private void applyValidatedChangesInTransaction(List<ValidatedChange> validatedChanges) { |
| | | private ApplyPersistenceResult persistApplyResultInTransaction(AiAutoTuneJob job, |
| | | AutoTuneApplyRequest request, |
| | | List<ValidatedChange> validatedChanges, |
| | | boolean dryRun, |
| | | Date now, |
| | | boolean writeTargets) { |
| | | TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager); |
| | | transactionTemplate.executeWithoutResult(status -> applyValidatedChanges(validatedChanges)); |
| | | return transactionTemplate.execute(status -> persistApplyResult( |
| | | job, |
| | | request, |
| | | validatedChanges, |
| | | dryRun, |
| | | now, |
| | | writeTargets |
| | | )); |
| | | } |
| | | |
| | | private void applyValidatedChanges(List<ValidatedChange> validatedChanges) { |
| | | private ApplyPersistenceResult persistApplyResult(AiAutoTuneJob job, |
| | | AutoTuneApplyRequest request, |
| | | List<ValidatedChange> validatedChanges, |
| | | boolean dryRun, |
| | | Date now, |
| | | boolean writeTargets) { |
| | | 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 boolean applyValidatedChanges(List<ValidatedChange> validatedChanges) { |
| | | boolean refreshConfigCache = false; |
| | | for (ValidatedChange validatedChange : validatedChanges) { |
| | | if (ChangeStatus.NO_CHANGE.equals(validatedChange.getStatus())) { |
| | |
| | | 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 refreshSystemConfigCacheIfNeeded(ApplyPersistenceResult persistenceResult) { |
| | | if (persistenceResult != null && persistenceResult.isRefreshConfigCache()) { |
| | | configService.refreshSystemConfigCache(); |
| | | } |
| | | } |
| | |
| | | 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 ValidatedChange { |
| | | private final AutoTuneChangeCommand command; |
| | | private final String targetType; |