From cb69777499e309414381cd3f04ff0ae2348d73f1 Mon Sep 17 00:00:00 2001 From: yahaozhang Date: Mon, 15 Sep 2025 15:30:10 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=88=A0=E9=99=A4=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E5=86=B7=E5=8D=B4=E7=9B=B8=E5=85=B3=E7=9A=84=E5=AE=9E=E4=BD=93?= =?UTF-8?q?=E3=80=81=E6=98=A0=E5=B0=84=E5=92=8C=E6=9C=8D=E5=8A=A1=EF=BC=8C?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/admin/CooldownController.java | 50 +++ .../cooldown/MachineCooldownMapper.java | 78 ----- .../dto/cooldown/CooldownStatsResponse.java | 34 ++ .../dto/cooldown/MachineCooldownView.java | 64 ++++ .../entity/cooldown/MachineCooldown.java | 185 ----------- .../cooldown/MachineCooldownService.java | 298 ------------------ .../MemoryMachineCooldownService.java | 40 +++ src/main/resources/application.yml | 2 +- .../db_migration_drop_machine_cooldown.sql | 9 + .../mapper/cooldown/MachineCooldownMapper.xml | 118 ------- 10 files changed, 198 insertions(+), 680 deletions(-) create mode 100644 src/main/java/com/gameplatform/server/controller/admin/CooldownController.java delete mode 100644 src/main/java/com/gameplatform/server/mapper/cooldown/MachineCooldownMapper.java create mode 100644 src/main/java/com/gameplatform/server/model/dto/cooldown/CooldownStatsResponse.java create mode 100644 src/main/java/com/gameplatform/server/model/dto/cooldown/MachineCooldownView.java delete mode 100644 src/main/java/com/gameplatform/server/model/entity/cooldown/MachineCooldown.java delete mode 100644 src/main/java/com/gameplatform/server/service/cooldown/MachineCooldownService.java create mode 100644 src/main/resources/db_migration_drop_machine_cooldown.sql delete mode 100644 src/main/resources/mapper/cooldown/MachineCooldownMapper.xml diff --git a/src/main/java/com/gameplatform/server/controller/admin/CooldownController.java b/src/main/java/com/gameplatform/server/controller/admin/CooldownController.java new file mode 100644 index 0000000..0b5a539 --- /dev/null +++ b/src/main/java/com/gameplatform/server/controller/admin/CooldownController.java @@ -0,0 +1,50 @@ +package com.gameplatform.server.controller.admin; + +import com.gameplatform.server.model.dto.cooldown.CooldownStatsResponse; +import com.gameplatform.server.model.dto.cooldown.MachineCooldownView; +import com.gameplatform.server.service.cooldown.MemoryMachineCooldownService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +@RequestMapping("/api/admin/cooldown") +@Tag(name = "机器冷却", description = "查询与管理内存中的机器冷却状态") +public class CooldownController { + + private final MemoryMachineCooldownService machineCooldownService; + + public CooldownController(MemoryMachineCooldownService machineCooldownService) { + this.machineCooldownService = machineCooldownService; + } + + @GetMapping("/list") + @Operation(summary = "列出冷却记录", description = "获取当前内存中的机器冷却记录") + public ResponseEntity> listCooldowns( + @Parameter(description = "仅返回仍在冷却中的记录") + @RequestParam(name = "activeOnly", required = false, defaultValue = "true") boolean activeOnly + ) { + List list = machineCooldownService.listAllCooldowns(activeOnly); + return ResponseEntity.ok(list); + } + + @GetMapping("/stats") + @Operation(summary = "冷却统计", description = "获取冷却总数、活跃数与总剩余分钟数") + public ResponseEntity getStats() { + MemoryMachineCooldownService.CooldownStats stats = machineCooldownService.getCooldownStats(); + CooldownStatsResponse body = new CooldownStatsResponse(true, + stats.getTotalDevices(), + stats.getActiveDevices(), + stats.getTotalRemainingMinutes()); + return ResponseEntity.ok(body); + } +} + + diff --git a/src/main/java/com/gameplatform/server/mapper/cooldown/MachineCooldownMapper.java b/src/main/java/com/gameplatform/server/mapper/cooldown/MachineCooldownMapper.java deleted file mode 100644 index 86ef0f1..0000000 --- a/src/main/java/com/gameplatform/server/mapper/cooldown/MachineCooldownMapper.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.gameplatform.server.mapper.cooldown; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.gameplatform.server.model.entity.cooldown.MachineCooldown; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; - -import java.time.LocalDateTime; -import java.util.List; - -/** - * 设备冷却状态Mapper - */ -@Mapper -public interface MachineCooldownMapper extends BaseMapper { - - /** - * 根据设备ID查找活跃的冷却记录 - */ - MachineCooldown findActiveCooldownByMachineId(@Param("machineId") String machineId); - - /** - * 根据设备ID和状态查找冷却记录 - */ - List findByMachineIdAndStatus(@Param("machineId") String machineId, - @Param("status") String status); - - /** - * 查找已过期但状态仍为ACTIVE的冷却记录 - */ - List findExpiredActiveCooldowns(@Param("currentTime") LocalDateTime currentTime, - @Param("limit") int limit); - - /** - * 批量更新过期的冷却记录状态 - */ - int batchUpdateExpiredCooldowns(@Param("currentTime") LocalDateTime currentTime); - - /** - * 手动移除设备的冷却状态 - */ - int removeMachineCooldown(@Param("machineId") String machineId); - - /** - * 根据链接任务ID查找冷却记录 - */ - List findByLinkTaskId(@Param("linkTaskId") Long linkTaskId); - - /** - * 统计活跃的冷却记录数量 - */ - long countActiveCooldowns(); - - /** - * 统计指定时间范围内的冷却记录数量 - */ - long countCooldownsByTimeRange(@Param("startTime") LocalDateTime startTime, - @Param("endTime") LocalDateTime endTime); - - /** - * 清理指定时间之前的已过期冷却记录 - */ - int cleanupExpiredCooldowns(@Param("beforeTime") LocalDateTime beforeTime); - - /** - * 删除将要过期(ACTIVE→EXPIRED)的设备,已存在的 EXPIRED 记录,避免唯一键 (machine_id,status) 冲突。 - * 使用当前时间参数筛选出需要过期的设备列表。 - */ - int deleteExistingExpiredForMachinesToExpire(@Param("currentTime") LocalDateTime currentTime); - - /** - * 获取指定设备的冷却历史记录 - */ - List getCooldownHistory(@Param("machineId") String machineId, - @Param("limit") int limit, - @Param("offset") int offset); -} - diff --git a/src/main/java/com/gameplatform/server/model/dto/cooldown/CooldownStatsResponse.java b/src/main/java/com/gameplatform/server/model/dto/cooldown/CooldownStatsResponse.java new file mode 100644 index 0000000..53deacd --- /dev/null +++ b/src/main/java/com/gameplatform/server/model/dto/cooldown/CooldownStatsResponse.java @@ -0,0 +1,34 @@ +package com.gameplatform.server.model.dto.cooldown; + +/** + * 冷却统计响应 + */ +public class CooldownStatsResponse { + private boolean success; + private int totalDevices; + private int activeDevices; + private long totalRemainingMinutes; + + public CooldownStatsResponse() {} + + public CooldownStatsResponse(boolean success, int totalDevices, int activeDevices, long totalRemainingMinutes) { + this.success = success; + this.totalDevices = totalDevices; + this.activeDevices = activeDevices; + this.totalRemainingMinutes = totalRemainingMinutes; + } + + public boolean isSuccess() { return success; } + public void setSuccess(boolean success) { this.success = success; } + + public int getTotalDevices() { return totalDevices; } + public void setTotalDevices(int totalDevices) { this.totalDevices = totalDevices; } + + public int getActiveDevices() { return activeDevices; } + public void setActiveDevices(int activeDevices) { this.activeDevices = activeDevices; } + + public long getTotalRemainingMinutes() { return totalRemainingMinutes; } + public void setTotalRemainingMinutes(long totalRemainingMinutes) { this.totalRemainingMinutes = totalRemainingMinutes; } +} + + diff --git a/src/main/java/com/gameplatform/server/model/dto/cooldown/MachineCooldownView.java b/src/main/java/com/gameplatform/server/model/dto/cooldown/MachineCooldownView.java new file mode 100644 index 0000000..6f5f462 --- /dev/null +++ b/src/main/java/com/gameplatform/server/model/dto/cooldown/MachineCooldownView.java @@ -0,0 +1,64 @@ +package com.gameplatform.server.model.dto.cooldown; + +import com.fasterxml.jackson.annotation.JsonFormat; + +import java.time.LocalDateTime; + +/** + * 内存冷却视图对象 + */ +public class MachineCooldownView { + private String machineId; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime cooldownStartTime; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime cooldownEndTime; + + private String reason; + private Long linkTaskId; + private long remainingMinutes; + private boolean active; + + public MachineCooldownView() {} + + public MachineCooldownView(String machineId, + LocalDateTime cooldownStartTime, + LocalDateTime cooldownEndTime, + String reason, + Long linkTaskId, + long remainingMinutes, + boolean active) { + this.machineId = machineId; + this.cooldownStartTime = cooldownStartTime; + this.cooldownEndTime = cooldownEndTime; + this.reason = reason; + this.linkTaskId = linkTaskId; + this.remainingMinutes = remainingMinutes; + this.active = active; + } + + public String getMachineId() { return machineId; } + public void setMachineId(String machineId) { this.machineId = machineId; } + + public LocalDateTime getCooldownStartTime() { return cooldownStartTime; } + public void setCooldownStartTime(LocalDateTime cooldownStartTime) { this.cooldownStartTime = cooldownStartTime; } + + public LocalDateTime getCooldownEndTime() { return cooldownEndTime; } + public void setCooldownEndTime(LocalDateTime cooldownEndTime) { this.cooldownEndTime = cooldownEndTime; } + + public String getReason() { return reason; } + public void setReason(String reason) { this.reason = reason; } + + public Long getLinkTaskId() { return linkTaskId; } + public void setLinkTaskId(Long linkTaskId) { this.linkTaskId = linkTaskId; } + + public long getRemainingMinutes() { return remainingMinutes; } + public void setRemainingMinutes(long remainingMinutes) { this.remainingMinutes = remainingMinutes; } + + public boolean isActive() { return active; } + public void setActive(boolean active) { this.active = active; } +} + + diff --git a/src/main/java/com/gameplatform/server/model/entity/cooldown/MachineCooldown.java b/src/main/java/com/gameplatform/server/model/entity/cooldown/MachineCooldown.java deleted file mode 100644 index d7bb59e..0000000 --- a/src/main/java/com/gameplatform/server/model/entity/cooldown/MachineCooldown.java +++ /dev/null @@ -1,185 +0,0 @@ -package com.gameplatform.server.model.entity.cooldown; - -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import com.fasterxml.jackson.annotation.JsonFormat; - -import java.time.LocalDateTime; - -/** - * 设备冷却状态实体 - */ -@TableName("machine_cooldown") -public class MachineCooldown { - - @TableId(type = IdType.AUTO) - private Long id; - - /** - * 设备ID - */ - private String machineId; - - /** - * 冷却开始时间 - */ - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private LocalDateTime cooldownStartTime; - - /** - * 冷却结束时间 - */ - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private LocalDateTime cooldownEndTime; - - /** - * 冷却原因 - */ - private String reason; - - /** - * 关联的链接任务ID - */ - private Long linkTaskId; - - /** - * 冷却状态:ACTIVE-活跃, EXPIRED-已过期, MANUALLY_REMOVED-手动移除 - */ - private String status; - - /** - * 创建时间 - */ - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private LocalDateTime createdAt; - - /** - * 更新时间 - */ - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private LocalDateTime updatedAt; - - // 构造函数 - public MachineCooldown() {} - - public MachineCooldown(String machineId, LocalDateTime cooldownStartTime, - LocalDateTime cooldownEndTime, String reason, Long linkTaskId) { - this.machineId = machineId; - this.cooldownStartTime = cooldownStartTime; - this.cooldownEndTime = cooldownEndTime; - this.reason = reason; - this.linkTaskId = linkTaskId; - this.status = "ACTIVE"; - this.createdAt = LocalDateTime.now(); - this.updatedAt = LocalDateTime.now(); - } - - // Getter and Setter methods - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getMachineId() { - return machineId; - } - - public void setMachineId(String machineId) { - this.machineId = machineId; - } - - public LocalDateTime getCooldownStartTime() { - return cooldownStartTime; - } - - public void setCooldownStartTime(LocalDateTime cooldownStartTime) { - this.cooldownStartTime = cooldownStartTime; - } - - public LocalDateTime getCooldownEndTime() { - return cooldownEndTime; - } - - public void setCooldownEndTime(LocalDateTime cooldownEndTime) { - this.cooldownEndTime = cooldownEndTime; - } - - public String getReason() { - return reason; - } - - public void setReason(String reason) { - this.reason = reason; - } - - public Long getLinkTaskId() { - return linkTaskId; - } - - public void setLinkTaskId(Long linkTaskId) { - this.linkTaskId = linkTaskId; - } - - public String getStatus() { - return status; - } - - public void setStatus(String status) { - this.status = status; - } - - public LocalDateTime getCreatedAt() { - return createdAt; - } - - public void setCreatedAt(LocalDateTime createdAt) { - this.createdAt = createdAt; - } - - public LocalDateTime getUpdatedAt() { - return updatedAt; - } - - public void setUpdatedAt(LocalDateTime updatedAt) { - this.updatedAt = updatedAt; - } - - /** - * 检查冷却是否仍然有效 - */ - public boolean isActive() { - return "ACTIVE".equals(status) && - cooldownEndTime != null && - LocalDateTime.now().isBefore(cooldownEndTime); - } - - /** - * 获取剩余冷却时间(分钟) - */ - public long getRemainingMinutes() { - if (!isActive()) { - return 0; - } - return java.time.Duration.between(LocalDateTime.now(), cooldownEndTime).toMinutes(); - } - - @Override - public String toString() { - return "MachineCooldown{" + - "id=" + id + - ", machineId='" + machineId + '\'' + - ", cooldownStartTime=" + cooldownStartTime + - ", cooldownEndTime=" + cooldownEndTime + - ", reason='" + reason + '\'' + - ", linkTaskId=" + linkTaskId + - ", status='" + status + '\'' + - ", createdAt=" + createdAt + - ", updatedAt=" + updatedAt + - '}'; - } -} - diff --git a/src/main/java/com/gameplatform/server/service/cooldown/MachineCooldownService.java b/src/main/java/com/gameplatform/server/service/cooldown/MachineCooldownService.java deleted file mode 100644 index 1595ba5..0000000 --- a/src/main/java/com/gameplatform/server/service/cooldown/MachineCooldownService.java +++ /dev/null @@ -1,298 +0,0 @@ -package com.gameplatform.server.service.cooldown; - -import com.gameplatform.server.mapper.cooldown.MachineCooldownMapper; -import com.gameplatform.server.model.entity.cooldown.MachineCooldown; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.time.LocalDateTime; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -/** - * 机器冷却服务 - 支持数据库持久化 - * 实现同一台机器在10分钟内不会重复调用的机制 - * - * 优化点: - * 1. 数据库持久化,服务重启不丢失状态 - * 2. 双重缓存机制,提高查询性能 - * 3. 分布式锁支持,避免并发问题 - */ -@Service -public class MachineCooldownService { - private static final Logger log = LoggerFactory.getLogger(MachineCooldownService.class); - - // 冷却时间:10分钟 - private static final int COOLDOWN_MINUTES = 10; - - // 内存缓存:machineId -> 最后操作时间(用于快速查询) - private final ConcurrentMap machineCooldownCache = new ConcurrentHashMap<>(); - - private final MachineCooldownMapper machineCooldownMapper; - - public MachineCooldownService(MachineCooldownMapper machineCooldownMapper) { - this.machineCooldownMapper = machineCooldownMapper; - // 启动时加载活跃的冷却记录到缓存 - loadActiveCooldownsToCache(); - } - - /** - * 启动时加载活跃的冷却记录到缓存 - */ - private void loadActiveCooldownsToCache() { - try { - List activeCooldowns = machineCooldownMapper.findExpiredActiveCooldowns( - LocalDateTime.now().plusMinutes(COOLDOWN_MINUTES), 1000); - - for (MachineCooldown cooldown : activeCooldowns) { - if (cooldown.isActive()) { - machineCooldownCache.put(cooldown.getMachineId(), cooldown.getCooldownStartTime()); - } - } - - log.info("加载了 {} 个活跃冷却记录到缓存", activeCooldowns.size()); - } catch (Exception e) { - log.error("加载冷却记录到缓存失败", e); - } - } - - /** - * 检查机器是否在冷却期内(优先从数据库查询确保准确性) - * @param machineId 机器ID - * @return true表示在冷却期内,false表示可以操作 - */ - public boolean isMachineInCooldown(String machineId) { - if (machineId == null || machineId.trim().isEmpty()) { - return false; - } - - try { - // 首先查询数据库获取最准确的状态 - MachineCooldown activeCooldown = machineCooldownMapper.findActiveCooldownByMachineId(machineId); - - if (activeCooldown == null || !activeCooldown.isActive()) { - // 数据库中没有活跃冷却记录,清理缓存 - machineCooldownCache.remove(machineId); - log.debug("机器{}没有活跃冷却记录,允许操作", machineId); - return false; - } - - // 更新缓存 - machineCooldownCache.put(machineId, activeCooldown.getCooldownStartTime()); - - long remainingMinutes = activeCooldown.getRemainingMinutes(); - log.info("机器{}在冷却期内,剩余冷却时间:{}分钟,原因:{}", - machineId, remainingMinutes + 1, activeCooldown.getReason()); - - return true; - - } catch (Exception e) { - log.error("检查机器{}冷却状态时发生异常,默认允许操作", machineId, e); - // 发生异常时,回退到缓存检查 - return isMachineInCooldownFromCache(machineId); - } - } - - /** - * 从缓存检查机器冷却状态(备用方法) - */ - private boolean isMachineInCooldownFromCache(String machineId) { - LocalDateTime lastOperationTime = machineCooldownCache.get(machineId); - if (lastOperationTime == null) { - return false; - } - - LocalDateTime now = LocalDateTime.now(); - LocalDateTime cooldownExpireTime = lastOperationTime.plusMinutes(COOLDOWN_MINUTES); - boolean inCooldown = now.isBefore(cooldownExpireTime); - - if (!inCooldown) { - // 冷却已过期,清理缓存 - machineCooldownCache.remove(machineId); - } - - return inCooldown; - } - - /** - * 将机器加入冷却队列(支持关联链接任务) - * @param machineId 机器ID - * @param reason 加入冷却的原因 - */ - @Transactional - public void addMachineToCooldown(String machineId, String reason) { - try { - addMachineToCooldown(machineId, reason, null); - } catch (RuntimeException ex) { - // 当上层已完成占用(或并发占用导致唯一键冲突)时,吞掉异常以便上层逻辑继续 - log.warn("添加冷却记录失败或已存在,machineId={},原因={}(忽略)", machineId, ex.getMessage()); - } - } - - /** - * 将机器加入冷却队列 - * @param machineId 机器ID - * @param reason 加入冷却的原因 - * @param linkTaskId 关联的链接任务ID(可选) - */ - @Transactional - public void addMachineToCooldown(String machineId, String reason, Long linkTaskId) { - if (machineId == null || machineId.trim().isEmpty()) { - log.warn("尝试添加空的机器ID到冷却队列"); - return; - } - - LocalDateTime now = LocalDateTime.now(); - LocalDateTime cooldownEndTime = now.plusMinutes(COOLDOWN_MINUTES); - - try { - // 先移除该设备现有的活跃冷却记录(若存在非并发场景下的残留) - machineCooldownMapper.removeMachineCooldown(machineId); - - // 创建新的冷却记录(依赖数据库唯一约束防止并发重复占用) - MachineCooldown cooldown = new MachineCooldown( - machineId, now, cooldownEndTime, reason, linkTaskId); - machineCooldownMapper.insert(cooldown); - - // 更新缓存 - machineCooldownCache.put(machineId, now); - - log.info("机器{}已加入冷却队列,原因:{},冷却时间:{}分钟,冷却结束时间:{},关联任务:{}", - machineId, reason, COOLDOWN_MINUTES, cooldownEndTime, linkTaskId); - - } catch (Exception e) { - log.error("将机器{}加入冷却队列失败:{}", machineId, e.getMessage(), e); - // 抛出异常,交由上层流程回滚/重试,避免同一设备被并发占用 - throw new RuntimeException("设备正忙或分配冲突,请稍后重试"); - } - } - - /** - * 获取机器剩余冷却时间(分钟) - * @param machineId 机器ID - * @return 剩余冷却时间,如果不在冷却期则返回0 - */ - public long getRemainingCooldownMinutes(String machineId) { - if (machineId == null || machineId.trim().isEmpty()) { - return 0; - } - - try { - MachineCooldown activeCooldown = machineCooldownMapper.findActiveCooldownByMachineId(machineId); - if (activeCooldown != null && activeCooldown.isActive()) { - return activeCooldown.getRemainingMinutes(); - } - } catch (Exception e) { - log.warn("查询机器{}剩余冷却时间失败,回退到缓存查询", machineId, e); - // 回退到缓存查询 - LocalDateTime lastOperationTime = machineCooldownCache.get(machineId); - if (lastOperationTime != null) { - LocalDateTime now = LocalDateTime.now(); - LocalDateTime cooldownExpireTime = lastOperationTime.plusMinutes(COOLDOWN_MINUTES); - if (now.isBefore(cooldownExpireTime)) { - return java.time.Duration.between(now, cooldownExpireTime).toMinutes() + 1; - } - } - } - - return 0; - } - - /** - * 手动移除机器的冷却状态(用于测试或管理员操作) - * @param machineId 机器ID - */ - @Transactional - public void removeMachineFromCooldown(String machineId) { - if (machineId == null || machineId.trim().isEmpty()) { - return; - } - - try { - int updated = machineCooldownMapper.removeMachineCooldown(machineId); - if (updated > 0) { - log.info("已手动移除机器{}的冷却状态", machineId); - } else { - log.debug("机器{}不在数据库冷却队列中", machineId); - } - } catch (Exception e) { - log.error("手动移除机器{}冷却状态失败", machineId, e); - } - - // 清理缓存 - LocalDateTime removedTime = machineCooldownCache.remove(machineId); - if (removedTime != null) { - log.debug("已从缓存中移除机器{}的冷却状态", machineId); - } - } - - /** - * 清理过期的冷却记录(可定期调用以释放内存) - */ - @Transactional - public void cleanupExpiredCooldowns() { - LocalDateTime now = LocalDateTime.now(); - - try { - // 批量更新数据库中过期的冷却记录 - int dbCleanedCount = machineCooldownMapper.batchUpdateExpiredCooldowns(now); - - // 清理缓存中过期的记录 - int cacheCleanedCount = 0; - var iterator = machineCooldownCache.entrySet().iterator(); - while (iterator.hasNext()) { - var entry = iterator.next(); - String machineId = entry.getKey(); - LocalDateTime lastOperationTime = entry.getValue(); - LocalDateTime cooldownExpireTime = lastOperationTime.plusMinutes(COOLDOWN_MINUTES); - - if (now.isAfter(cooldownExpireTime)) { - iterator.remove(); - cacheCleanedCount++; - } - } - - if (dbCleanedCount > 0 || cacheCleanedCount > 0) { - log.info("清理过期冷却记录完成:数据库{}个,缓存{}个", dbCleanedCount, cacheCleanedCount); - } - - } catch (Exception e) { - log.error("清理过期冷却记录失败", e); - } - } - - /** - * 获取当前冷却队列的大小 - * @return 冷却队列中的机器数量 - */ - public int getCooldownQueueSize() { - try { - return (int) machineCooldownMapper.countActiveCooldowns(); - } catch (Exception e) { - log.warn("查询活跃冷却记录数量失败,返回缓存大小", e); - return machineCooldownCache.size(); - } - } - - /** - * 获取机器的冷却历史记录 - * @param machineId 机器ID - * @param limit 返回记录数量限制 - * @return 冷却历史记录列表 - */ - public List getCooldownHistory(String machineId, int limit) { - if (machineId == null || machineId.trim().isEmpty()) { - return List.of(); - } - - try { - return machineCooldownMapper.getCooldownHistory(machineId, limit, 0); - } catch (Exception e) { - log.error("查询机器{}冷却历史失败", machineId, e); - return List.of(); - } - } -} diff --git a/src/main/java/com/gameplatform/server/service/cooldown/MemoryMachineCooldownService.java b/src/main/java/com/gameplatform/server/service/cooldown/MemoryMachineCooldownService.java index a866c5b..fa1414e 100644 --- a/src/main/java/com/gameplatform/server/service/cooldown/MemoryMachineCooldownService.java +++ b/src/main/java/com/gameplatform/server/service/cooldown/MemoryMachineCooldownService.java @@ -3,8 +3,13 @@ package com.gameplatform.server.service.cooldown; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; +import com.gameplatform.server.model.dto.cooldown.MachineCooldownView; import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.locks.ReentrantLock; @@ -226,6 +231,41 @@ public class MemoryMachineCooldownService { return cooldownMap.size(); } + /** + * 列出内存中的所有冷却记录 + * @param activeOnly 是否仅返回仍在冷却中的记录 + */ + public List listAllCooldowns(boolean activeOnly) { + // 主动清理一次,避免返回过期项 + cleanupExpiredCooldowns(); + + List result = new ArrayList<>(); + for (Map.Entry entry : cooldownMap.entrySet()) { + String machineId = entry.getKey(); + CooldownInfo info = entry.getValue(); + boolean active = info.isActive(); + if (activeOnly && !active) { + continue; + } + + long remaining = active ? info.getRemainingMinutes() : 0L; + result.add(new MachineCooldownView( + machineId, + info.getCooldownStartTime(), + info.getCooldownEndTime(), + info.getReason(), + info.getLinkTaskId(), + remaining, + active + )); + } + + // 便于排查:按结束时间升序排列 + result.sort(Comparator.comparing(MachineCooldownView::getCooldownEndTime, + Comparator.nullsLast(Comparator.naturalOrder()))); + return result; + } + /** * 清理过期的冷却记录 */ diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 6754065..74831fe 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -88,7 +88,7 @@ script: # 服务器配置 app: - base-url: "https://2.uzi0.cc" # 生产环境需要配置为实际域名 + base-url: "https://uzi1.cn" # 生产环境需要配置为实际域名 # base-url: "http://localhost:18080" # 本地测试环境 link: diff --git a/src/main/resources/db_migration_drop_machine_cooldown.sql b/src/main/resources/db_migration_drop_machine_cooldown.sql new file mode 100644 index 0000000..25bd5a2 --- /dev/null +++ b/src/main/resources/db_migration_drop_machine_cooldown.sql @@ -0,0 +1,9 @@ +-- 清理未使用的设备冷却表 +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +DROP TABLE IF EXISTS `machine_cooldown`; + +SET FOREIGN_KEY_CHECKS = 1; + + diff --git a/src/main/resources/mapper/cooldown/MachineCooldownMapper.xml b/src/main/resources/mapper/cooldown/MachineCooldownMapper.xml deleted file mode 100644 index 7b76f25..0000000 --- a/src/main/resources/mapper/cooldown/MachineCooldownMapper.xml +++ /dev/null @@ -1,118 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - UPDATE machine_cooldown mc - LEFT JOIN ( - SELECT machine_id FROM ( - SELECT DISTINCT machine_id - FROM machine_cooldown - WHERE status = 'EXPIRED' - ) ex0 - ) ex ON ex.machine_id = mc.machine_id - SET mc.status = 'EXPIRED', mc.updated_at = NOW() - WHERE mc.status = 'ACTIVE' - AND mc.cooldown_end_time <= #{currentTime} - AND ex.machine_id IS NULL - - - - - UPDATE machine_cooldown - SET status = 'MANUALLY_REMOVED', updated_at = NOW() - WHERE machine_id = #{machineId} - AND status = 'ACTIVE' - - - - - - - - - - - - - - DELETE FROM machine_cooldown - WHERE status = 'EXPIRED' - AND updated_at < #{beforeTime} - - - - - DELETE mc FROM machine_cooldown mc - JOIN ( - SELECT DISTINCT machine_id - FROM machine_cooldown - WHERE status = 'ACTIVE' - AND cooldown_end_time <= #{currentTime} - ) t ON t.machine_id = mc.machine_id - WHERE mc.status = 'EXPIRED' - - - - - - -