From f91f550e8e2d52b9b4300dffe0067bb57bbdae6d Mon Sep 17 00:00:00 2001 From: tianfeng <769204422@qq.com> Date: Wed, 12 Nov 2025 18:08:28 +0800 Subject: [PATCH] =?UTF-8?q?=E7=81=AB=E7=AE=AD=E5=8D=87=E7=BA=A7=E5=AE=8C?= =?UTF-8?q?=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../enums/message/GroupMessageTypeEnum.java | 10 + .../command/rocket/RocketEnergyAddCmdExe.java | 93 +----- .../command/rocket/RocketLaunchCmdExe.java | 61 ++-- .../other/app/config/RocketAsyncConfig.java | 60 ++++ .../app/listener/gift/GiveGiftsListener.java | 2 +- .../gift/strategy/GiftSendRocketListener.java | 112 +++++++- .../app/manager/RocketEnergyAggregator.java | 265 ++++++++++++++++++ .../app/manager/RocketImPushManager.java | 31 +- .../app/manager/RocketLaunchManager.java | 35 +++ .../app/scheduler/RocketClaimExpireTask.java | 57 ---- .../other/domain/rocket/RocketLevel.java | 19 ++ .../other/domain/rocket/RocketStatus.java | 113 +++++--- .../other/domain/rocket/RocketStatusEnum.java | 9 +- .../repository/RocketStatusRepository.java | 6 +- .../live/RoomProfileManagerService.java | 2 + .../impl/RoomProfileManagerServiceImpl.java | 55 +++- 16 files changed, 692 insertions(+), 238 deletions(-) create mode 100644 rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/config/RocketAsyncConfig.java create mode 100644 rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/manager/RocketEnergyAggregator.java create mode 100644 rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/manager/RocketLaunchManager.java delete mode 100644 rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/scheduler/RocketClaimExpireTask.java diff --git a/rc-service/rc-inner-api/external-inner/external-inner-model/src/main/java/com/red/circle/external/inner/model/enums/message/GroupMessageTypeEnum.java b/rc-service/rc-inner-api/external-inner/external-inner-model/src/main/java/com/red/circle/external/inner/model/enums/message/GroupMessageTypeEnum.java index ef3bc92f..263d6cbb 100644 --- a/rc-service/rc-inner-api/external-inner/external-inner-model/src/main/java/com/red/circle/external/inner/model/enums/message/GroupMessageTypeEnum.java +++ b/rc-service/rc-inner-api/external-inner/external-inner-model/src/main/java/com/red/circle/external/inner/model/enums/message/GroupMessageTypeEnum.java @@ -131,4 +131,14 @@ public enum GroupMessageTypeEnum { */ GAME_BAISHUN_WIN, + /** + * 火箭能力值更新 + */ + ROCKET_ENERGY_UPDATE, + + /** + * 火箭发射 + */ + ROCKET_ENERGY_LAUNCH, + } diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/rocket/RocketEnergyAddCmdExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/rocket/RocketEnergyAddCmdExe.java index 0cba6686..f25e5113 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/rocket/RocketEnergyAddCmdExe.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/rocket/RocketEnergyAddCmdExe.java @@ -1,18 +1,14 @@ package com.red.circle.other.app.command.rocket; import com.red.circle.other.app.dto.cmd.RocketEnergyAddCmd; -import com.red.circle.other.app.util.DistributedLockUtil; -import com.red.circle.other.domain.gateway.RocketStatusGateway; -import com.red.circle.other.domain.rocket.RocketStatus; -import com.red.circle.other.infra.database.cache.key.RocketKeys; +import com.red.circle.other.app.manager.RocketEnergyAggregator; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; -import java.time.LocalDate; - /** * 火箭能量增加命令执行器 + * 优化版:使用异步聚合,避免频繁锁竞争和推送 * * @author system * @date 2025-01-15 @@ -22,89 +18,16 @@ import java.time.LocalDate; @RequiredArgsConstructor public class RocketEnergyAddCmdExe { - private final RocketStatusGateway rocketStatusGateway; - private final DistributedLockUtil distributedLockUtil; - private final RocketLaunchCmdExe rocketLaunchCmdExe; + private final RocketEnergyAggregator rocketEnergyAggregator; /** - * 幸运礼物加成比例 - */ - private static final double LUCKY_BONUS_RATE = 0.04; - - /** - * 执行能量增加 + * 执行能量增加(异步聚合) */ public void execute(RocketEnergyAddCmd cmd) { - // 构建锁Key - String lockKey = RocketKeys.LOCK.getKey(cmd.getRoomId()); + // 直接提交到聚合器,不加锁 + rocketEnergyAggregator.addEnergy(cmd); - // 使用分布式锁执行 - distributedLockUtil.executeWithLock(lockKey, 5L, () -> { - doAddEnergy(cmd); - return null; - }, "火箭能量增加操作过于频繁,请稍后重试"); - } - - /** - * 执行能量增加逻辑 - */ - private void doAddEnergy(RocketEnergyAddCmd cmd) { - // 1. 查询当前火箭状态 - String today = LocalDate.now().toString(); - RocketStatus rocketStatus = rocketStatusGateway.findByRoomIdAndDate(cmd.getRoomId(), today); - - if (rocketStatus == null) { - // 初始化火箭 - rocketStatus = RocketStatus.init(cmd.getRoomId()); - log.info("初始化房间火箭, roomId={}", cmd.getRoomId()); - } - - // 2. 校验状态 - if (!rocketStatus.canAddEnergy()) { - log.warn("火箭不可充能, roomId={}, status={}", cmd.getRoomId(), rocketStatus.getStatus()); - return; - } - - // 3. 计算能量值 - long energyValue = calculateEnergy(cmd); - - // 4. 增加能量 - rocketStatus.addEnergy( - cmd.getUserId(), - cmd.getUserName(), - cmd.getUserAvatar(), - energyValue - ); - - // 5. 保存状态 - rocketStatusGateway.save(rocketStatus); - - log.info("火箭能量增加成功, roomId={}, userId={}, energy={}, currentEnergy={}, level={}", - cmd.getRoomId(), cmd.getUserId(), energyValue, - rocketStatus.getCurrentEnergy(), rocketStatus.getLevel().getLevel()); - - // 6. 检查是否需要发射 - if (rocketStatus.isFullEnergy()) { - log.info("火箭能量已满, 准备发射, roomId={}, level={}, finalEnergy={}", - cmd.getRoomId(), rocketStatus.getLevel().getLevel(), rocketStatus.getCurrentEnergy()); - - // 触发发射 - rocketLaunchCmdExe.execute(cmd.getRoomId()); - } - } - - /** - * 计算能量值 - */ - private long calculateEnergy(RocketEnergyAddCmd cmd) { - long baseEnergy = cmd.getGiftGoldValue(); - - if (Boolean.TRUE.equals(cmd.getIsLucky())) { - // 幸运礼物额外增加4% - long luckyBonus = (long) (baseEnergy * LUCKY_BONUS_RATE); - return baseEnergy + luckyBonus; - } - - return baseEnergy; + log.debug("提交火箭能量增加任务: roomId={}, userId={}, energy={}", + cmd.getRoomId(), cmd.getUserId(), cmd.getGiftGoldValue()); } } diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/rocket/RocketLaunchCmdExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/rocket/RocketLaunchCmdExe.java index d36b3a9c..f268a0af 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/rocket/RocketLaunchCmdExe.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/rocket/RocketLaunchCmdExe.java @@ -4,12 +4,14 @@ import com.red.circle.other.app.convertor.RocketConvertor; import com.red.circle.other.app.dto.clientobject.RocketStatusCO; import com.red.circle.other.app.manager.RocketImPushManager; import com.red.circle.other.app.util.DistributedLockUtil; +import com.red.circle.other.domain.gateway.RocketConfigGateway; import com.red.circle.other.domain.gateway.RocketHistoryGateway; import com.red.circle.other.domain.gateway.RocketStatusGateway; import com.red.circle.other.domain.rocket.RocketHistory; import com.red.circle.other.domain.rocket.RocketStatus; import com.red.circle.other.domain.rocket.RocketStatusEnum; import com.red.circle.other.infra.database.cache.key.RocketKeys; +import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -18,6 +20,7 @@ import java.time.LocalDate; /** * 火箭发射命令执行器 + * 优化版:发射后自动升级到下一级火箭 * * @author system * @date 2025-01-15 @@ -31,16 +34,16 @@ public class RocketLaunchCmdExe { private final RocketHistoryGateway rocketHistoryGateway; private final DistributedLockUtil distributedLockUtil; private final RocketImPushManager rocketImPushManager; + private final RocketConfigGateway rocketConfigGateway; + private final RoomProfileManagerService roomProfileManagerService; /** * 执行火箭发射 */ public void execute(Long roomId) { - // 构建锁Key String lockKey = RocketKeys.LOCK.getKey(roomId); - // 使用分布式锁执行 - distributedLockUtil.executeWithLock(lockKey, 5L, () -> { + distributedLockUtil.executeWithLock(lockKey, 10L, () -> { doLaunch(roomId); return null; }, "火箭发射操作过于频繁,请稍后重试"); @@ -50,7 +53,7 @@ public class RocketLaunchCmdExe { * 执行发射逻辑 */ private void doLaunch(Long roomId) { - // 1. 查询当前火箭状态 + // 1. 查询当前火箭状态(需要完整数据,包含贡献者) String today = LocalDate.now().toString(); RocketStatus rocketStatus = rocketStatusGateway.findByRoomIdAndDate(roomId, today); @@ -72,37 +75,53 @@ public class RocketLaunchCmdExe { return; } - // 4. 发射火箭 - rocketStatus.launch(); + // 4. 记录发射前的等级(用于日志和历史) + int launchedLevel = rocketStatus.getLevel().getLevel(); + long finalEnergy = rocketStatus.getCurrentEnergy(); + int contributorCount = rocketStatus.getContributors() != null ? rocketStatus.getContributors().size() : 0; - // 5. 立即进入领取状态 - rocketStatus.startClaiming(); - - // 6. 保存状态 - rocketStatusGateway.save(rocketStatus); - - // 7. 保存历史记录 + // 5. 保存历史记录(发射前保存,保留贡献者信息) try { RocketHistory history = RocketHistory.fromRocketStatus(rocketStatus); String historyId = rocketHistoryGateway.save(history); - log.info("保存火箭历史记录成功: historyId={}, roomId={}", historyId, roomId); + log.info("保存火箭历史记录成功: historyId={}, roomId={}, level={}", historyId, roomId, launchedLevel); } catch (Exception e) { log.error("保存火箭历史记录失败: roomId={}", roomId, e); } - // 8. 推送发射动画消息 + // 6. 推送发射动画消息(发射前推送,包含贡献者信息) try { RocketStatusCO statusCO = RocketConvertor.toStatusCO(rocketStatus); - rocketImPushManager.pushRocketLaunch(roomId, statusCO); + rocketImPushManager.pushRocketLaunch( statusCO); } catch (Exception e) { log.error("推送火箭发射消息失败: roomId={}", roomId, e); } - log.info("火箭发射成功, roomId={}, level={}, finalEnergy={}, contributors={}, launchTime={}", + // 7. 发射并自动升级到下一级 + rocketStatus.launchAndUpgrade(rocketConfigGateway); + + // 8. 保存新状态 + rocketStatusGateway.save(rocketStatus); + + log.info("火箭发射并升级成功: roomId={}, 发射等级={}, 最终能量={}, 贡献者数={}, 升级到={}", roomId, - rocketStatus.getLevel().getLevel(), - rocketStatus.getCurrentEnergy(), - rocketStatus.getContributors() != null ? rocketStatus.getContributors().size() : 0, - rocketStatus.getLaunchTime()); + launchedLevel, + finalEnergy, + contributorCount, + rocketStatus.getLevel().getLevel()); + + // 9. 如果升级成功,推送升级消息 + if (rocketStatus.getLevel().getLevel() > launchedLevel) { + try { + RocketStatusCO newStatusCO = RocketConvertor.toStatusCO(rocketStatus); + String roomAccount = roomProfileManagerService.getRoomAccount(roomId); + rocketImPushManager.pushEnergyUpdate(roomAccount, newStatusCO); + + String upgradeMsg = launchedLevel == 3 ? "重置为一级火箭" : "升级到" + rocketStatus.getLevel().getName(); + log.info("推送火箭升级消息: roomId={}, {}", roomId, upgradeMsg); + } catch (Exception e) { + log.error("推送火箭升级消息失败: roomId={}", roomId, e); + } + } } } diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/config/RocketAsyncConfig.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/config/RocketAsyncConfig.java new file mode 100644 index 00000000..024db71b --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/config/RocketAsyncConfig.java @@ -0,0 +1,60 @@ +package com.red.circle.other.app.config; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.Executor; +import java.util.concurrent.ThreadPoolExecutor; + +/** + * 火箭异步任务配置 + * + * @author system + * @date 2025-01-15 + */ +@Slf4j +@Configuration +@EnableAsync +@EnableScheduling +public class RocketAsyncConfig { + + /** + * 火箭任务线程池 + */ + @Bean("rocketTaskExecutor") + public Executor rocketTaskExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + + // 核心线程数 + executor.setCorePoolSize(5); + + // 最大线程数 + executor.setMaxPoolSize(10); + + // 队列容量 + executor.setQueueCapacity(100); + + // 线程名前缀 + executor.setThreadNamePrefix("rocket-task-"); + + // 拒绝策略:调用者运行 + executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + + // 线程空闲时间(秒) + executor.setKeepAliveSeconds(60); + + // 关闭时等待任务完成 + executor.setWaitForTasksToCompleteOnShutdown(true); + executor.setAwaitTerminationSeconds(60); + + executor.initialize(); + + log.info("火箭任务线程池初始化完成"); + + return executor; + } +} diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/listener/gift/GiveGiftsListener.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/listener/gift/GiveGiftsListener.java index 19c2f298..57664e69 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/listener/gift/GiveGiftsListener.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/listener/gift/GiveGiftsListener.java @@ -400,7 +400,7 @@ public class GiveGiftsListener implements MessageListener { offlineProcessGiftEvent(OfflineStatisticsGiftEventType.RANK_COUNT, runningWater); // 钻石统计相关 - offlineProcessGiftEvent(OfflineStatisticsGiftEventType.DIAMOND_COUNT, runningWater); + offlineProcessGiftEvent(OfflineStatisticsGiftEventType.ROCKET_COUNT, runningWater); } private Pair saveRunningWater(GiveAwayGiftBatchEvent event) { diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/listener/gift/strategy/GiftSendRocketListener.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/listener/gift/strategy/GiftSendRocketListener.java index 440cb5be..60d6f422 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/listener/gift/strategy/GiftSendRocketListener.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/listener/gift/strategy/GiftSendRocketListener.java @@ -1,14 +1,28 @@ package com.red.circle.other.app.listener.gift.strategy; +import com.alibaba.fastjson.JSON; import com.red.circle.mq.business.model.event.gift.OfflineProcessGiftEvent; -import com.red.circle.other.app.service.RocketService; +import com.red.circle.other.app.command.rocket.RocketEnergyAddCmdExe; +import com.red.circle.other.app.common.gift.GameLuckyGiftCommon; +import com.red.circle.other.app.dto.cmd.RocketEnergyAddCmd; +import com.red.circle.other.infra.database.cache.service.other.RoomManagerCacheService; +import com.red.circle.other.infra.database.mongo.entity.gift.GiftAcceptUser; +import com.red.circle.other.infra.database.mongo.entity.gift.GiftGiveRunningWater; +import com.red.circle.other.infra.database.mongo.entity.gift.GiftValue; +import com.red.circle.other.infra.database.mongo.service.gift.GiftGiveRunningWaterService; +import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService; +import com.red.circle.other.inner.enums.material.GiftCurrencyType; +import com.red.circle.other.inner.enums.material.GiftTabEnum; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; import org.springframework.stereotype.Service; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.Objects; + /** - * 火箭统计相关 + * 火箭统计相关 - 礼物送出时增加火箭能量 * * @author system * @date 2025-01-15 @@ -16,14 +30,100 @@ import org.springframework.stereotype.Service; @Slf4j @Service("ROCKET_COUNT_LISTENER") @RequiredArgsConstructor -public class GiftSendRocketListener implements GiftStrategy { - - private final RocketService rocketService; +public class GiftSendRocketListener implements GiftStrategy { + private final RocketEnergyAddCmdExe rocketEnergyAddCmdExe; + private final GiftGiveRunningWaterService giftGiveRunningWaterService; + private final GameLuckyGiftCommon gameLuckyGiftCommon; + private final RoomProfileManagerService roomProfileManagerService; @Override public void processor(OfflineProcessGiftEvent event) { + log.info("【火箭能量增加】接收礼物事件: {}", JSON.toJSONString(event)); + // 1. 查询礼物流水 + GiftGiveRunningWater runningWater = giftGiveRunningWaterService.getByIdPrimary( + event.getRunningWaterId()); + + if (Objects.isNull(runningWater)) { + log.warn("【火箭能量增加】没有找到流水信息,忽略处理"); + return; + } + + // 2. 只处理金币礼物 + if (!GiftCurrencyType.GOLD.eq(runningWater.getGiftValue().getCurrencyType())) { + log.debug("【火箭能量增加】非金币礼物,跳过处理"); + return; + } + + giftGiveRunningWaterService.addLog(runningWater.getId(), "开始:火箭能量增加"); + + try { + // 3. 获取礼物信息 + GiftValue giftValue = runningWater.getGiftValue(); + + // 4. 判断是否为幸运礼物 + boolean isLuckyGift = isLuckyGift(giftValue); + + // 5. 获取幸运礼物比例 + BigDecimal luckyGiftRatio = BigDecimal.ZERO; + if (isLuckyGift) { + luckyGiftRatio = gameLuckyGiftCommon.getLuckyGiftShareRatio(runningWater.getSysOrigin()); + log.info("【火箭能量增加】幸运礼物比例:{}", luckyGiftRatio); + } + + // 6. 计算实际金币价值(考虑幸运礼物加成) + Long actualGoldValue = getActualAmount(isLuckyGift, giftValue.getActualAmount(), luckyGiftRatio); + + // 7. 只处理在房间内送出的礼物 + String originId = runningWater.getOriginId(); + if (originId == null || !originId.matches("\\d+")) { + log.debug("【火箭能量增加】非房间场景,跳过处理"); + return; + } + + Long roomId = Long.parseLong(originId); + + // 8. 获取送礼用户信息 + Long userId = runningWater.getUserId(); + + // 9. 构建命令并执行 + RocketEnergyAddCmd cmd = new RocketEnergyAddCmd(); + cmd.setRoomId(roomId); + cmd.setUserId(userId); + cmd.setGiftGoldValue(actualGoldValue); + cmd.setIsLucky(isLuckyGift); + + rocketEnergyAddCmdExe.execute(cmd); + + log.info("【火箭能量增加】处理成功: roomId={}, userId={}, goldValue={}, isLucky={}", + roomId, userId, actualGoldValue, isLuckyGift); + + } catch (Exception e) { + log.error("【火箭能量增加】处理异常: runningWaterId={}", runningWater.getId(), e); + } finally { + giftGiveRunningWaterService.addLog(runningWater.getId(), "结束:火箭能量增加"); + } } + /** + * 判断是否为幸运礼物 + */ + private boolean isLuckyGift(GiftValue giftValue) { + return giftValue.getGiftType() != null && + giftValue.getGiftType().contains(GiftTabEnum.LUCKY_GIFT.name()); + } + + /** + * 计算实际金额(考虑幸运礼物加成) + */ + private Long getActualAmount(boolean isLuckyGift, BigDecimal amount, BigDecimal luckyGiftRatio) { + if (isLuckyGift && luckyGiftRatio != null && luckyGiftRatio.compareTo(BigDecimal.ZERO) > 0) { + // 幸运礼物按比例计算 + return amount.multiply(luckyGiftRatio) + .setScale(0, RoundingMode.DOWN) + .longValue(); + } + return amount.longValue(); + } } diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/manager/RocketEnergyAggregator.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/manager/RocketEnergyAggregator.java new file mode 100644 index 00000000..b37cd635 --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/manager/RocketEnergyAggregator.java @@ -0,0 +1,265 @@ +package com.red.circle.other.app.manager; + +import com.red.circle.other.app.convertor.RocketConvertor; +import com.red.circle.other.app.dto.clientobject.RocketStatusCO; +import com.red.circle.other.app.dto.cmd.RocketEnergyAddCmd; +import com.red.circle.other.app.util.DistributedLockUtil; +import com.red.circle.other.domain.gateway.RocketConfigGateway; +import com.red.circle.other.domain.gateway.RocketStatusGateway; +import com.red.circle.other.domain.rocket.RocketConfig; +import com.red.circle.other.domain.rocket.RocketStatus; +import com.red.circle.other.infra.database.cache.key.RocketKeys; +import com.red.circle.other.infra.database.mongo.entity.live.RoomProfileManager; +import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService; +import com.red.circle.other.infra.gateway.RocketStatusGatewayImpl; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReentrantLock; + +/** + * 火箭能量聚合器 + * 职责: + * 1. 接收能量增加请求,缓存到内存 + * 2. 定时批量刷新到数据库 + * 3. 定时推送能量更新消息 + * + * @author system + * @date 2025-01-15 + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class RocketEnergyAggregator { + + private final RocketStatusGateway rocketStatusGateway; + private final RocketStatusGatewayImpl rocketStatusGatewayImpl; + private final DistributedLockUtil distributedLockUtil; + private final RocketConfigGateway rocketConfigGateway; + private final RocketImPushManager rocketImPushManager; + private final RocketLaunchManager rocketLaunchManager; + private final RoomProfileManagerService roomProfileManagerService; + + /** + * 房间能量聚合缓存 + * Key: roomId + * Value: 该房间待聚合的能量列表 + */ + private final Map> energyBuffer = new ConcurrentHashMap<>(); + + /** + * 房间级别的细粒度锁 + * Key: roomId + * Value: 该房间的锁 + */ + private final Map roomLocks = new ConcurrentHashMap<>(); + + /** + * 推送间隔(毫秒) + */ + private static final long PUSH_INTERVAL = 3000L; // 3秒推送一次 + + /** + * 批量刷新间隔(毫秒) + */ + private static final long FLUSH_INTERVAL = 5000L; // 5秒刷新一次 + + /** + * 上次推送时间 + * Key: roomId + * Value: 上次推送的时间戳 + */ + private final Map lastPushTime = new ConcurrentHashMap<>(); + + /** + * 接收能量增加请求(无锁,直接缓存) + */ + public void addEnergy(RocketEnergyAddCmd cmd) { + energyBuffer.computeIfAbsent(cmd.getRoomId(), k -> new ArrayList<>()).add(cmd); + + log.debug("缓存火箭能量: roomId={}, userId={}, energy={}, bufferSize={}", + cmd.getRoomId(), cmd.getUserId(), cmd.getGiftGoldValue(), + energyBuffer.get(cmd.getRoomId()).size()); + } + + /** + * 定时批量刷新到数据库(每5秒) + */ + @Scheduled(fixedDelay = FLUSH_INTERVAL) + public void flushToDatabase() { + if (energyBuffer.isEmpty()) { + return; + } + + log.info("开始批量刷新火箭能量, 待处理房间数={}", energyBuffer.size()); + + // 遍历所有房间 + energyBuffer.forEach((roomId, cmdList) -> { + if (cmdList.isEmpty()) { + return; + } + + try { + // 获取该房间的细粒度锁 + ReentrantLock roomLock = roomLocks.computeIfAbsent(roomId, k -> new ReentrantLock()); + + if (roomLock.tryLock()) { + try { + // 取出当前批次的数据 + List batch = new ArrayList<>(cmdList); + cmdList.clear(); + + // 处理这个房间的能量增加 + processRoomEnergy(roomId, batch); + + } finally { + roomLock.unlock(); + } + } else { + log.debug("房间{}正在处理中,跳过本次刷新", roomId); + } + } catch (Exception e) { + log.error("刷新房间{}火箭能量失败", roomId, e); + } + }); + } + + /** + * 处理单个房间的能量增加 + */ + private void processRoomEnergy(Long roomId, List cmdList) { + if (cmdList.isEmpty()) { + return; + } + + String lockKey = RocketKeys.LOCK.getKey(roomId); + + // 使用Redis分布式锁,避免多实例冲突 + distributedLockUtil.executeWithLock(lockKey, 10L, () -> { + + // 1. 查询当前火箭状态(不包含贡献者列表,性能优化) + String today = LocalDate.now().toString(); + RocketStatus rocketStatus = rocketStatusGatewayImpl + .findByRoomIdAndDateWithoutContributors(roomId, today); + + if (rocketStatus == null) { + // 查询一级火箭配置 + RocketConfig level1Config = rocketConfigGateway.findByLevel(1); + if (level1Config == null || level1Config.getStatus() != 1) { + log.error("一级火箭配置不存在或未启用"); + return null; + } + + // 使用配置初始化 + rocketStatus = RocketStatus.init(roomId, level1Config); + log.info("初始化房间火箭, roomId={}, maxEnergy={}", roomId, level1Config.getMaxEnergy()); + } + + // 2. 检查状态 + if (!rocketStatus.canAddEnergy()) { + log.warn("火箭不可充能, roomId={}, status={}", roomId, rocketStatus.getStatus()); + return null; + } + + // 3. 批量增加能量 + long totalEnergy = 0L; + for (RocketEnergyAddCmd cmd : cmdList) { + rocketStatus.addEnergy( + cmd.getUserId(), + cmd.getGiftGoldValue() + ); + totalEnergy += cmd.getGiftGoldValue(); + } + + // 4. 保存状态(一次性保存) + rocketStatusGateway.save(rocketStatus); + + log.info("批量增加火箭能量: roomId={}, 批次数量={}, 总能量={}, 当前能量={}/{}", + roomId, cmdList.size(), totalEnergy, + rocketStatus.getCurrentEnergy(), rocketStatus.getMaxEnergy()); + + // 5. 推送更新消息(节流) + String roomAccount = roomProfileManagerService.getRoomAccount(roomId); + pushEnergyUpdate(roomId, roomAccount, rocketStatus); + + // 6. 检查是否需要发射 + if (rocketStatus.isFullEnergy()) { + log.info("火箭能量已满, 准备发射, roomId={}, level={}", + roomId, rocketStatus.getLevel().getLevel()); + + // 异步触发发射 + rocketLaunchManager.launchAsync(roomId); + } + + return null; + }, "火箭能量刷新操作中,请稍后"); + } + + /** + * 推送能量更新(节流:3秒推送一次) + */ + private void pushEnergyUpdate(Long roomId, String roomAccount, RocketStatus rocketStatus) { + long now = System.currentTimeMillis(); + Long lastPush = lastPushTime.get(roomId); + + // 节流:距离上次推送不足3秒,跳过 + if (lastPush != null && (now - lastPush) < PUSH_INTERVAL) { + log.debug("推送节流:距离上次推送{}ms,跳过本次推送", now - lastPush); + return; + } + + try { + // 查询火箭状态 + RocketStatus fullStatus = rocketStatusGatewayImpl + .findByRoomIdAndDateWithoutContributors(roomId, rocketStatus.getDate()); + + if (fullStatus != null) { + RocketStatusCO statusCO = RocketConvertor.toStatusCO(fullStatus); + rocketImPushManager.pushEnergyUpdate(roomAccount, statusCO); + + // 更新推送时间 + lastPushTime.put(roomId, now); + + log.info("推送火箭能量更新: roomId={}, energy={}/{}", + roomId, fullStatus.getCurrentEnergy(), fullStatus.getMaxEnergy()); + } + } catch (Exception e) { + log.error("推送火箭能量更新失败: roomId={}", roomId, e); + } + } + + /** + * 定时清理空闲房间的锁(每小时) + */ + @Scheduled(fixedRate = 3600000) + public void cleanupIdleRooms() { + // 清理buffer中的空列表 + energyBuffer.entrySet().removeIf(entry -> entry.getValue().isEmpty()); + + // 清理不在buffer中的锁 + roomLocks.keySet().removeIf(roomId -> !energyBuffer.containsKey(roomId)); + + // 清理推送时间 + lastPushTime.keySet().removeIf(roomId -> !energyBuffer.containsKey(roomId)); + + log.info("清理空闲房间资源, 当前活跃房间数={}", energyBuffer.size()); + } + + /** + * 应用关闭时强制刷新 + */ + @javax.annotation.PreDestroy + public void shutdown() { + log.info("应用关闭,强制刷新所有待处理能量"); + flushToDatabase(); + } +} diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/manager/RocketImPushManager.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/manager/RocketImPushManager.java index ebfc57b8..62e6530f 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/manager/RocketImPushManager.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/manager/RocketImPushManager.java @@ -31,45 +31,39 @@ public class RocketImPushManager { /** * 推送能量更新消息 */ - public void pushEnergyUpdate(Long roomId, RocketStatusCO status) { + public void pushEnergyUpdate(String roomAccount, RocketStatusCO status) { try { - // 构建消息 - ImMessage message = buildEnergyUpdateMessage(status); - - imGroupClient.sendCustomMessage(String.valueOf(roomId), + imGroupClient.sendCustomMessage(roomAccount, CustomGroupMsgBodyCmd.builder() - .type(GroupMessageTypeEnum.GAME_LUCKY_GIFT) - .data(message) + .type(GroupMessageTypeEnum.ROCKET_ENERGY_UPDATE) + .data(status) .build()); log.info("推送火箭能量更新消息成功: roomId={}, level={}, energy={}/{}", - roomId, status.getLevel(), status.getCurrentEnergy(), status.getMaxEnergy()); + roomAccount, status.getLevel(), status.getCurrentEnergy(), status.getMaxEnergy()); } catch (Exception e) { - log.error("推送火箭能量更新消息失败: roomId={}", roomId, e); + log.error("推送火箭能量更新消息失败: roomId={}", roomAccount, e); } } /** * 推送火箭发射消息 */ - public void pushRocketLaunch(Long roomId, RocketStatusCO status) { + public void pushRocketLaunch(RocketStatusCO status) { try { - // 构建消息 - ImMessage message = buildLaunchMessage(status); - imGroupClient.sendMessageBroadcast( BroadcastGroupMsgBodyCmd.builder() .toPlatform(SysOriginPlatformEnum.LIKEI) - .type(GroupMessageTypeEnum.GAME_LUCKY_GIFT) - .data(message) + .type(GroupMessageTypeEnum.ROCKET_ENERGY_LAUNCH) + .data(status) .build() ); - log.info("推送火箭发射消息成功: roomId={}, level={}", roomId, status.getLevel()); + log.info("推送火箭发射消息成功: roomId={}, level={}", status.getRoomId(), status.getLevel()); } catch (Exception e) { - log.error("推送火箭发射消息失败: roomId={}", roomId, e); + log.error("推送火箭发射消息失败: roomId={}", status.getRoomId(), e); } } @@ -155,8 +149,7 @@ public class RocketImPushManager { } /** - * IM消息对象(示例) - * TODO: 替换为实际的IM消息类 + * IM消息对象 */ private static class ImMessage { private String type; diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/manager/RocketLaunchManager.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/manager/RocketLaunchManager.java new file mode 100644 index 00000000..61305e25 --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/manager/RocketLaunchManager.java @@ -0,0 +1,35 @@ +package com.red.circle.other.app.manager; + +import com.red.circle.other.app.command.rocket.RocketLaunchCmdExe; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +/** + * 火箭发射管理器 + * 职责:异步处理火箭发射 + * + * @author system + * @date 2025-01-15 + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class RocketLaunchManager { + + private final RocketLaunchCmdExe rocketLaunchCmdExe; + + /** + * 异步发射火箭 + */ + @Async("rocketTaskExecutor") + public void launchAsync(Long roomId) { + try { + log.info("异步执行火箭发射: roomId={}", roomId); + rocketLaunchCmdExe.execute(roomId); + } catch (Exception e) { + log.error("异步火箭发射失败: roomId={}", roomId, e); + } + } +} diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/scheduler/RocketClaimExpireTask.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/scheduler/RocketClaimExpireTask.java deleted file mode 100644 index a5c2e0cb..00000000 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/scheduler/RocketClaimExpireTask.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.red.circle.other.app.scheduler; - -import com.red.circle.other.domain.gateway.RocketStatusGateway; -import com.red.circle.other.domain.rocket.RocketStatus; -import com.red.circle.other.domain.rocket.RocketStatusEnum; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; - -import java.time.LocalDate; -import java.util.List; - -/** - * 火箭领取过期检查任务 - * - * @author system - * @date 2025-01-15 - */ -@Slf4j -@Component -@RequiredArgsConstructor -public class RocketClaimExpireTask { - - private final RocketStatusGateway rocketStatusGateway; - - /** - * 每分钟检查一次过期状态 - */ - @Scheduled(fixedRate = 60000) - public void checkExpire() { - try { - String today = LocalDate.now().toString(); - - // 查询所有处于充能状态的火箭 (包含CLAIMING状态) - List allRockets = rocketStatusGateway.findAllCharging(today); - - for (RocketStatus rocketStatus : allRockets) { - // 检查是否过期 - if (rocketStatus.getStatus() == RocketStatusEnum.CLAIMING && rocketStatus.isExpired()) { - log.info("火箭领取已过期, 开始重置, roomId={}, claimExpireTime={}", - rocketStatus.getRoomId(), rocketStatus.getClaimExpireTime()); - - // TODO: 保存历史记录 - - // 重置火箭 - rocketStatus.reset(); - rocketStatusGateway.save(rocketStatus); - - log.info("过期火箭重置成功, roomId={}", rocketStatus.getRoomId()); - } - } - } catch (Exception e) { - log.error("火箭过期检查任务执行失败", e); - } - } -} diff --git a/rc-service/rc-service-other/other-domain/src/main/java/com/red/circle/other/domain/rocket/RocketLevel.java b/rc-service/rc-service-other/other-domain/src/main/java/com/red/circle/other/domain/rocket/RocketLevel.java index 585dbf34..c6bacba5 100644 --- a/rc-service/rc-service-other/other-domain/src/main/java/com/red/circle/other/domain/rocket/RocketLevel.java +++ b/rc-service/rc-service-other/other-domain/src/main/java/com/red/circle/other/domain/rocket/RocketLevel.java @@ -55,6 +55,25 @@ public enum RocketLevel { throw new IllegalArgumentException("不支持的火箭等级: " + level); } + /** + * 获取下一级火箭 + * @return 下一级火箭,如果已是最高级则返回null + */ + public RocketLevel getNextLevel() { + return switch (this) { + case LEVEL_1 -> LEVEL_2; + case LEVEL_2 -> LEVEL_3; + case LEVEL_3 -> null; // 三级是最高级,返回null表示需要重置 + }; + } + + /** + * 是否是最高级 + */ + public boolean isMaxLevel() { + return this == LEVEL_3; + } + /** * 根据能量值判断等级 */ diff --git a/rc-service/rc-service-other/other-domain/src/main/java/com/red/circle/other/domain/rocket/RocketStatus.java b/rc-service/rc-service-other/other-domain/src/main/java/com/red/circle/other/domain/rocket/RocketStatus.java index 68c68cb9..5927a5fc 100644 --- a/rc-service/rc-service-other/other-domain/src/main/java/com/red/circle/other/domain/rocket/RocketStatus.java +++ b/rc-service/rc-service-other/other-domain/src/main/java/com/red/circle/other/domain/rocket/RocketStatus.java @@ -1,6 +1,8 @@ package com.red.circle.other.domain.rocket; +import com.red.circle.other.domain.gateway.RocketConfigGateway; import lombok.Data; +import lombok.extern.slf4j.Slf4j; import java.math.BigDecimal; import java.math.RoundingMode; @@ -17,6 +19,7 @@ import java.util.List; * @date 2025-01-15 */ @Data +@Slf4j public class RocketStatus { /** @@ -87,13 +90,13 @@ public class RocketStatus { /** * 初始化火箭 */ - public static RocketStatus init(Long roomId) { + public static RocketStatus init(Long roomId, RocketConfig config) { RocketStatus rocketStatus = new RocketStatus(); rocketStatus.setRoomId(roomId); rocketStatus.setDate(LocalDate.now().toString()); - rocketStatus.setLevel(RocketLevel.LEVEL_1); + rocketStatus.setLevel(RocketLevel.of(config.getLevel())); rocketStatus.setCurrentEnergy(0L); - rocketStatus.setMaxEnergy(RocketLevel.LEVEL_1.getMaxEnergy()); + rocketStatus.setMaxEnergy(config.getMaxEnergy()); rocketStatus.setStatus(RocketStatusEnum.CHARGING); rocketStatus.setContributors(new ArrayList<>()); rocketStatus.setClaimCount(0); @@ -101,52 +104,100 @@ public class RocketStatus { rocketStatus.setUpdatedAt(LocalDateTime.now()); return rocketStatus; } - /** * 增加能量 */ - public void addEnergy(Long userId, String userName, String userAvatar, Long energyValue) { - // 增加总能量 + public void addEnergy(Long userId,Long energyValue) { this.currentEnergy += energyValue; - // 更新贡献者 RocketContributor contributor = findContributor(userId); if (contributor == null) { contributor = new RocketContributor(); contributor.setUserId(userId); - contributor.setUserName(userName); - contributor.setUserAvatar(userAvatar); contributor.setEnergy(0L); contributor.setGiftCount(0); + contributor.setFirstContributeTime(LocalDateTime.now()); this.contributors.add(contributor); } contributor.addEnergy(energyValue); + contributor.setLastContributeTime(LocalDateTime.now()); - // 重新计算贡献率 recalculateContributionRate(); - - // 检查等级提升 - checkAndUpgradeLevel(); - this.updatedAt = LocalDateTime.now(); } + // RocketStatus.java + /** - * 发射火箭 + * 升级到下一级火箭(使用配置) */ - public void launch() { + private void upgradeToNextLevel(RocketConfigGateway configGateway) { + RocketLevel nextLevel = this.level.getNextLevel(); + + if (nextLevel != null) { + // 查询下一级配置 + RocketConfig nextConfig = configGateway.findByLevel(nextLevel.getLevel()); + if (nextConfig == null || nextConfig.getStatus() != 1) { + log.warn("下一级火箭配置不存在或未启用, level={}", nextLevel.getLevel()); + return; + } + + // 计算溢出能量(当前能量 - 当前等级最大能量) + long overflowEnergy = this.currentEnergy - this.maxEnergy; + if (overflowEnergy < 0) { + overflowEnergy = 0L; + } + + // 升级到下一级 + this.level = nextLevel; + this.maxEnergy = nextConfig.getMaxEnergy(); + this.currentEnergy = overflowEnergy; // 保留溢出能量 + this.status = RocketStatusEnum.CHARGING; + + // 清空贡献者(新一轮) + this.contributors = new ArrayList<>(); + this.launchTime = null; + this.claimExpireTime = null; + + log.info("火箭升级成功, 升至{}级, 溢出能量={}, 新目标={}", + nextLevel.getLevel(), overflowEnergy, this.maxEnergy); + } else { + // 已经是最高级,重置为一级 +// reset(configGateway); + } + } + + /** + * 发射火箭并自动升级(需要传入配置网关) + */ + public void launchAndUpgrade(RocketConfigGateway configGateway) { this.status = RocketStatusEnum.LAUNCHED; this.launchTime = LocalDateTime.now(); - // 领取过期时间:发射后1分钟 - this.claimExpireTime = LocalDateTime.now().plusMinutes(1); this.updatedAt = LocalDateTime.now(); + + // 升级到下一级 + upgradeToNextLevel(configGateway); } /** - * 开始领取 + * 重置状态(使用一级配置) */ - public void startClaiming() { - this.status = RocketStatusEnum.CLAIMING; + public void reset(RocketConfigGateway configGateway) { + // 查询一级配置 + RocketConfig level1Config = configGateway.findByLevel(1); + if (level1Config == null) { + throw new RuntimeException("一级火箭配置不存在"); + } + + this.date = LocalDate.now().toString(); + this.level = RocketLevel.LEVEL_1; + this.currentEnergy = 0L; + this.maxEnergy = level1Config.getMaxEnergy(); + this.status = RocketStatusEnum.CHARGING; + this.contributors = new ArrayList<>(); + this.launchTime = null; + this.claimExpireTime = null; + this.claimCount = 0; this.updatedAt = LocalDateTime.now(); } @@ -162,7 +213,7 @@ public class RocketStatus { } /** - * 重置状态 + * 重置状态(三级发射后重置为一级) */ public void reset() { this.date = LocalDate.now().toString(); @@ -192,12 +243,10 @@ public class RocketStatus { } /** - * 是否可以领取 + * 是否可以领取(已移除CLAIMING状态) */ public boolean canClaim() { - return this.status == RocketStatusEnum.CLAIMING - && this.claimExpireTime != null - && LocalDateTime.now().isBefore(this.claimExpireTime); + return false; // 暂时隐藏领取功能 } /** @@ -249,18 +298,6 @@ public class RocketStatus { contributor.setContributionRate(rate); }); - // 按贡献能量排序 this.contributors.sort(Comparator.comparing(RocketContributor::getEnergy).reversed()); } - - /** - * 检查并升级等级 - */ - private void checkAndUpgradeLevel() { - RocketLevel newLevel = RocketLevel.determineLevel(this.currentEnergy); - if (newLevel != this.level) { - this.level = newLevel; - this.maxEnergy = newLevel.getMaxEnergy(); - } - } } diff --git a/rc-service/rc-service-other/other-domain/src/main/java/com/red/circle/other/domain/rocket/RocketStatusEnum.java b/rc-service/rc-service-other/other-domain/src/main/java/com/red/circle/other/domain/rocket/RocketStatusEnum.java index 29ffdc53..910f8c46 100644 --- a/rc-service/rc-service-other/other-domain/src/main/java/com/red/circle/other/domain/rocket/RocketStatusEnum.java +++ b/rc-service/rc-service-other/other-domain/src/main/java/com/red/circle/other/domain/rocket/RocketStatusEnum.java @@ -19,14 +19,9 @@ public enum RocketStatusEnum { CHARGING(1, "充能中"), /** - * 已发射 + * 已发射(等待下一级) */ - LAUNCHED(2, "已发射"), - - /** - * 领取中 - */ - CLAIMING(3, "领取中"); + LAUNCHED(2, "已发射"); /** * 状态码 diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/repository/RocketStatusRepository.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/repository/RocketStatusRepository.java index 70374e97..4f58ea4e 100644 --- a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/repository/RocketStatusRepository.java +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/repository/RocketStatusRepository.java @@ -27,21 +27,21 @@ public interface RocketStatusRepository extends MongoRepository findByRoomIdAndDateWithoutContributors(Long roomId, String date); /** * 根据房间ID和日期查询(只包含Top N贡献者) * 用于:前端展示Top榜单的场景 */ - @Query(value = "{ 'room_id': ?0, 'date': ?1 }", + @Query(value = "{ 'roomId': ?0, 'date': ?1 }", fields = "{ 'contributors': { $slice: ?2 } }") Optional findByRoomIdAndDateWithTopContributors(Long roomId, String date, Integer topN); /** * 根据房间ID列表和日期查询(排除贡献者列表) */ - @Query(value = "{ 'room_id': { $in: ?0 }, 'date': ?1 }", fields = "{ 'contributors': 0 }") + @Query(value = "{ 'roomId': { $in: ?0 }, 'date': ?1 }", fields = "{ 'contributors': 0 }") List findByRoomIdInAndDateWithoutContributors(List roomIds, String date); /** diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/live/RoomProfileManagerService.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/live/RoomProfileManagerService.java index 75baafee..6aecb186 100644 --- a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/live/RoomProfileManagerService.java +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/live/RoomProfileManagerService.java @@ -17,6 +17,8 @@ import java.util.Set; */ public interface RoomProfileManagerService { + String getRoomAccount(Long roomId); + /** * 用户是否存在房间. */ diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/live/impl/RoomProfileManagerServiceImpl.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/live/impl/RoomProfileManagerServiceImpl.java index 65fd8129..650c9d4a 100644 --- a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/live/impl/RoomProfileManagerServiceImpl.java +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/live/impl/RoomProfileManagerServiceImpl.java @@ -26,14 +26,18 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; import java.util.function.Function; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Sort; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Update; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; /** @@ -43,9 +47,58 @@ import org.springframework.stereotype.Service; */ @Service @RequiredArgsConstructor +@Slf4j public class RoomProfileManagerServiceImpl implements RoomProfileManagerService { - private final MongoTemplate mongoTemplate; + private final MongoTemplate mongoTemplate; + private final RedisTemplate redisTemplate; + + /** + * Redis缓存Key前缀 + */ + private static final String ROOM_ACCOUNT_CACHE_KEY = "rocket:room:account:"; + + /** + * Redis缓存过期时间(1小时) + */ + private static final long ROOM_ACCOUNT_CACHE_EXPIRE = 3600L; + + /** + * 获取房间Account(带Redis缓存) + * + * @param roomId 房间ID + * @return 房间Account + */ + @Override + public String getRoomAccount(Long roomId) { + if (roomId == null) { + return ""; + } + + // 1. 先查Redis缓存 + String cacheKey = ROOM_ACCOUNT_CACHE_KEY + roomId; + String account = redisTemplate.opsForValue().get(cacheKey); + if (account != null) { + return account; + } + + // 2. 查MongoDB + try { + RoomProfile roomProfile = getById(roomId); + if (roomProfile != null && roomProfile.getRoomAccount() != null) { + account = roomProfile.getRoomAccount(); + + // 写入Redis缓存 + redisTemplate.opsForValue().set(cacheKey, account, ROOM_ACCOUNT_CACHE_EXPIRE, TimeUnit.SECONDS); + + return account; + } + } catch (Exception e) { + log.error("查询房间Account失败: roomId={}", roomId, e); + } + + return ""; + } @Override public boolean existsUserRoom(Long userId) {