红包可能出现的异常问题处理修复

This commit is contained in:
tianfeng 2025-11-26 17:15:28 +08:00
parent 4709b6f535
commit cdd73bfc03
2 changed files with 14 additions and 15 deletions

View File

@ -57,7 +57,7 @@ public class GrabRoomRedPacketCmdExe {
if (packetData == null || packetData.isEmpty()) { if (packetData == null || packetData.isEmpty()) {
// Redis未命中从数据库加载 // Redis未命中从数据库加载
RoomRedPacket redPacket = roomRedPacketGateway.findByPacketId(packetId); RoomRedPacket redPacket = roomRedPacketGateway.findByPacketId(packetId);
ResponseAssert.notNull(OtherErrorCode.RED_PACKET_NOT_FOUND, grabbed); ResponseAssert.notNull(OtherErrorCode.RED_PACKET_NOT_FOUND, redPacket);
// 检查状态 // 检查状态
checkRedPacketStatus(redPacket); checkRedPacketStatus(redPacket);
@ -81,7 +81,7 @@ public class GrabRoomRedPacketCmdExe {
ResponseAssert.isFalse(OtherErrorCode.RED_PACKET_FINISHED, remainCount == null || remainCount < 0); ResponseAssert.isFalse(OtherErrorCode.RED_PACKET_FINISHED, remainCount == null || remainCount < 0);
// 6. 设置防重标记Redis // 6. 设置防重标记Redis
long expireSeconds = Duration.between(LocalDateTime.now(), expireTime).getSeconds(); long expireSeconds = Math.max(60, Duration.between(LocalDateTime.now(), expireTime).getSeconds());
boolean setSuccess = roomRedPacketCacheService.setUserGrabbedFlag(packetId, userId, expireSeconds); boolean setSuccess = roomRedPacketCacheService.setUserGrabbedFlag(packetId, userId, expireSeconds);
ResponseAssert.isTrue(OtherErrorCode.RED_PACKET_ALREADY_GRABBED, setSuccess); ResponseAssert.isTrue(OtherErrorCode.RED_PACKET_ALREADY_GRABBED, setSuccess);
@ -221,7 +221,7 @@ public class GrabRoomRedPacketCmdExe {
"status", redPacket.getStatus() "status", redPacket.getStatus()
); );
long expireSeconds = Duration.between(LocalDateTime.now(), redPacket.getExpireTime()).getSeconds() + 600; long expireSeconds = Duration.between(LocalDateTime.now(), redPacket.getExpireTime()).getSeconds();
roomRedPacketCacheService.setRedPacket(redPacket.getPacketId(), packetData, expireSeconds); roomRedPacketCacheService.setRedPacket(redPacket.getPacketId(), packetData, expireSeconds);
} }
} }

View File

@ -61,33 +61,32 @@ public class SendRoomRedPacketCmdExe {
Long userId = cmd.getReqUserId(); Long userId = cmd.getReqUserId();
cmd.setPacketType(2); cmd.setPacketType(2);
// 1. 参数校验 // 参数校验
validateParams(cmd); validateParams(cmd);
// 2. 生成红包ID
String packetId = IdWorkerUtils.getIdStr(); String packetId = IdWorkerUtils.getIdStr();
// 3. 扣除用户金币同步调用钱包服务 // 计算过期时间
deductUserGold(userId, cmd, packetId);
// 4. 计算过期时间
LocalDateTime expireTime = LocalDateTime.now().plusMinutes(cmd.getExpireMinutes()); LocalDateTime expireTime = LocalDateTime.now().plusMinutes(cmd.getExpireMinutes());
// 5. 创建红包记录 // 创建红包记录
RoomRedPacket redPacket = buildRedPacket(cmd, userId, packetId, expireTime); RoomRedPacket redPacket = buildRedPacket(cmd, userId, packetId, expireTime);
roomRedPacketGateway.save(redPacket); roomRedPacketGateway.save(redPacket);
// 扣除用户金币同步调用钱包服务
deductUserGold(userId, cmd, packetId);
// 6. 拼手气红包预生成随机金额列表 // 拼手气红包预生成随机金额列表
if (RoomRedPacketType.RANDOM.getCode().equals(cmd.getPacketType())) { if (RoomRedPacketType.RANDOM.getCode().equals(cmd.getPacketType())) {
List<Long> amounts = generateRandomAmounts(cmd.getTotalAmount(), cmd.getTotalCount()); List<Long> amounts = generateRandomAmounts(cmd.getTotalAmount(), cmd.getTotalCount());
long expireSeconds = cmd.getExpireMinutes() * 60; long expireSeconds = cmd.getExpireMinutes() * 60;
roomRedPacketCacheService.setRandomAmounts(packetId, amounts, expireSeconds); roomRedPacketCacheService.setRandomAmounts(packetId, amounts, expireSeconds);
} }
// 7. 写入Redis红包主数据 // 写入Redis红包主数据
cacheRedPacketData(redPacket); cacheRedPacketData(redPacket);
// 8. 添加到房间红包列表 // 添加到房间红包列表
roomRedPacketCacheService.addToRoomList( roomRedPacketCacheService.addToRoomList(
cmd.getRoomId(), cmd.getRoomId(),
packetId, packetId,
@ -216,11 +215,11 @@ public class SendRoomRedPacketCmdExe {
List<Long> amounts = new ArrayList<>(totalCount); List<Long> amounts = new ArrayList<>(totalCount);
long remainAmount = totalAmount; long remainAmount = totalAmount;
int remainCount = totalCount; int remainCount = totalCount;
for (int i = 0; i < totalCount - 1; i++) { for (int i = 0; i < totalCount - 1; i++) {
// 二倍均值法随机金额范围 [1, 剩余平均值 * 2] // 二倍均值法随机金额范围 [1, 剩余平均值 * 2]
long avgAmount = remainAmount / remainCount; long avgAmount = remainAmount / remainCount;
long maxAmount = avgAmount * 2; long maxAmount = Math.min(avgAmount * 2, remainAmount - (remainCount - 1)); // 保证剩余够分
// 确保至少1金币 // 确保至少1金币
long amount = ThreadLocalRandom.current().nextLong(1, Math.max(2, maxAmount + 1)); long amount = ThreadLocalRandom.current().nextLong(1, Math.max(2, maxAmount + 1));