diff --git a/accompany-business/accompany-business-sdk/src/main/java/com/accompany/business/dto/lucky/Lucky24GiftConfig.java b/accompany-business/accompany-business-sdk/src/main/java/com/accompany/business/dto/lucky/Lucky24GiftConfig.java index 339b047d3..9c6037076 100644 --- a/accompany-business/accompany-business-sdk/src/main/java/com/accompany/business/dto/lucky/Lucky24GiftConfig.java +++ b/accompany-business/accompany-business-sdk/src/main/java/com/accompany/business/dto/lucky/Lucky24GiftConfig.java @@ -6,6 +6,7 @@ import java.math.BigDecimal; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TreeMap; @Data public class Lucky24GiftConfig { @@ -63,11 +64,26 @@ public class Lucky24GiftConfig { private BigDecimal storeRatio; private Integer startHour; private Integer endHour; + @Deprecated private Integer inputThreshold; + @Deprecated private Set userRechargeLevels; + @Deprecated private BigDecimal todayProductionRatio; + @Deprecated private Long todayDiff; + @Deprecated private Integer twoDayCountLimit; + + private Integer dayCountLimit; + private List timesJudgeArray; + private Map userRechargeLevelJudgeConfigMap; + + @Data + public static class UserRechargeLevelJudgeConfig{ + private int historyTimes; + private TreeMap productionRatioMultipleMap; + } } } diff --git a/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/gift/Lucky24GiftSendService.java b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/gift/Lucky24GiftSendService.java index f27dd46da..2110c4c62 100644 --- a/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/gift/Lucky24GiftSendService.java +++ b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/gift/Lucky24GiftSendService.java @@ -102,22 +102,24 @@ public class Lucky24GiftSendService { private Map draw(Lucky24GiftConfig config, Lucky24GiftConfig partitionConfig, long senderUid, Integer partitionId, Gift gift, int everyGiftNum, long everyoneGoldNum, List receiverList, Room room, Date sendGiftTime, boolean extraSwitch) { - if (!extraSwitch){ + if (!extraSwitch + || config.getBlackUidList().contains(senderUid) + || userMetaService.getTimes(senderUid) <= (long) config.getNewUserPoolCount() * config.getPoolSize()){ return draw(config, partitionConfig, senderUid, partitionId, gift, everyGiftNum, everyoneGoldNum, receiverList, room, sendGiftTime); } Lucky24GiftConfig.Lucky24ExtraPoolConfig extraPoolConfig = partitionConfig.getExtraPoolConfig(); - Long extraLucker = extraService.selectExtraLucker(extraPoolConfig, senderUid, partitionId, everyoneGoldNum, receiverList); - if (null == extraLucker){ + Long extraLuckerUid = extraService.selectExtraLucker(extraPoolConfig, senderUid, partitionId, receiverList); + if (null == extraLuckerUid){ return draw(config, partitionConfig, senderUid, partitionId, gift, everyGiftNum, everyoneGoldNum, receiverList, room, sendGiftTime); } - Lucky24Record extraRecord = extraService.randomExtraRecord(config, senderUid, partitionId, extraLucker, gift, everyGiftNum, everyoneGoldNum, room, sendGiftTime); + Lucky24Record extraRecord = extraService.randomExtraRecord(config, extraPoolConfig, senderUid, partitionId, extraLuckerUid, gift, everyGiftNum, everyoneGoldNum, room, sendGiftTime); List receiverUidList = new ArrayList<>(receiverList); - receiverUidList.remove(extraLucker); + receiverUidList.remove(extraLuckerUid); Map recordMap = draw(config, partitionConfig, senderUid, partitionId, gift, everyGiftNum, everyoneGoldNum, receiverUidList, room, sendGiftTime); - recordMap.put(extraLucker, extraRecord); + recordMap.put(extraLuckerUid, extraRecord); return recordMap; } diff --git a/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/lucky/Lucky24ExtraService.java b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/lucky/Lucky24ExtraService.java index 55e8f3161..4f67d0a2b 100644 --- a/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/lucky/Lucky24ExtraService.java +++ b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/lucky/Lucky24ExtraService.java @@ -2,6 +2,7 @@ package com.accompany.business.service.lucky; import com.accompany.business.constant.Lucky24PoolTypeEnum; import com.accompany.business.dto.lucky.Lucky24GiftConfig; +import com.accompany.business.dto.lucky.Lucky24Result; import com.accompany.business.model.Gift; import com.accompany.common.utils.DateTimeUtil; import com.accompany.common.utils.RandomUtil; @@ -10,7 +11,9 @@ import com.accompany.core.model.Room; import com.accompany.payment.service.UserRechargeLevelService; import com.accompany.sharding.model.Lucky24Record; import com.accompany.sharding.vo.Lucky24StockResultVo; +import com.alibaba.fastjson2.JSON; import lombok.extern.slf4j.Slf4j; +import org.redisson.api.RList; import org.redisson.api.RMap; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -18,9 +21,7 @@ import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.ZonedDateTime; -import java.util.Date; -import java.util.List; -import java.util.Map; +import java.util.*; @Slf4j @Service @@ -38,83 +39,109 @@ public class Lucky24ExtraService { private Lucky24SettlementService settlementService; @Autowired private Lucky24RecordService recordService; - public BigDecimal addStock(Integer partitionId, BigDecimal addScore) { return stockService.addStock(partitionId, addScore); } - public Long selectExtraLucker(Lucky24GiftConfig.Lucky24ExtraPoolConfig extraPoolConfig, long senderUid, Integer partitionId, long everyoneGoldNum, List receiverList) { + public Long selectExtraLucker(Lucky24GiftConfig.Lucky24ExtraPoolConfig extraPoolConfig, long senderUid, Integer partitionId, List receiverList) { PartitionEnum partitionEnum = PartitionEnum.getByPartitionId(partitionId); ZonedDateTime zdt = DateTimeUtil.getDateTimeByZoneId(partitionEnum.getZoneId()); if (zdt.getHour() < extraPoolConfig.getStartHour() || zdt.getHour() > extraPoolConfig.getEndHour()){ return null; } - if (everyoneGoldNum < extraPoolConfig.getInputThreshold()){ - return null; - } - - String userRechargeLevel = userRechargeLevelService.getLevelByUid(senderUid); - if (!extraPoolConfig.getUserRechargeLevels().contains(userRechargeLevel)){ - return null; - } - RMap userMetaMap = userMetaService.getUserMeta(senderUid); Map userMetaSnapshot = userMetaMap.readAllMap(); long todayStartTimeLong = DateTimeUtil.getZonedTodayTime(partitionEnum.getZoneId()); String today = String.valueOf(todayStartTimeLong); - String todayInputKey = String.join("_", today, Lucky24UserMetaService.INPUT_KEY); - long todayInput = userMetaSnapshot.getOrDefault(todayInputKey, 0L).longValue(); - String todayOutputKey = String.join("_", today, Lucky24UserMetaService.OUTPUT_KEY); - long todayOutput = userMetaSnapshot.getOrDefault(todayOutputKey, 0L).longValue(); - BigDecimal todayProductionRatio = todayInput > 0L && todayOutput > 0L ? BigDecimal.valueOf(todayOutput).divide(BigDecimal.valueOf(todayInput), 4, RoundingMode.HALF_UP) : BigDecimal.ZERO; - if (todayProductionRatio.compareTo(extraPoolConfig.getTodayProductionRatio()) >= 0){ - log.info("[lucky24] extra todayProductionRation fail uid {} partitionId {} todayInput {} todayOutput {} pr {} configPr {}", - senderUid, partitionId, todayInput, todayOutput, todayProductionRatio, extraPoolConfig.getTodayProductionRatio()); + String todayDayCountKey = String.join("_", today, Lucky24UserMetaService.EXTRA_POOL_COUNT); + int todayDayCount = userMetaSnapshot.getOrDefault(todayDayCountKey, 0).intValue(); + if (todayDayCount >= extraPoolConfig.getDayCountLimit()){ return null; } - long todayDiff = todayInput - todayOutput; - if (todayDiff < extraPoolConfig.getTodayDiff()){ - log.info("[lucky24] extra todayDiff fail uid {} partitionId {} todayInput {} todayOutput {} todayDiff {} configTodayDiff {}", - senderUid, partitionId, todayInput, todayOutput, todayDiff, extraPoolConfig.getTodayDiff()); - return null; - } + String todayTimesKey = String.join("_", today, Lucky24UserMetaService.TIMES_KEY); + long todayTimes = userMetaSnapshot.getOrDefault(todayTimesKey, 0L).longValue(); - String yesterday = zdt.minusDays(1L).format(DateTimeUtil.dateFormatter); - String lastTwoDayKey = String.join("_", Lucky24UserMetaService.EXTRA_POOL_COUNT, yesterday); - int lastTwoDayCount = userMetaSnapshot.getOrDefault(lastTwoDayKey, 0).intValue(); - if (lastTwoDayCount >= extraPoolConfig.getTwoDayCountLimit()){ - return null; - } + List timesJudgeList = extraPoolConfig.getTimesJudgeArray(); + int maxJudgeTimes = timesJudgeList.get(timesJudgeList.size() - 1); - int expectedValue = lastTwoDayCount + 1; - int result = userMetaMap.compute(lastTwoDayKey, (key, currentVal) -> { - if (currentVal == null || currentVal.intValue() == lastTwoDayCount) { - return expectedValue; + Long luckyer = null; + + long todayTimesBefore = todayTimes; + for (Long receiver: receiverList){ + long todayTimesAfter = todayTimesBefore + 1; + if (todayTimesBefore < maxJudgeTimes){ + + for (Integer judgeTimes: timesJudgeList){ + if (todayTimesBefore < judgeTimes && todayTimesAfter >= judgeTimes){ + luckyer = receiver; + break; + } else if (judgeTimes == maxJudgeTimes && todayTimesAfter >= maxJudgeTimes){ + long beforeMod = todayTimesBefore % maxJudgeTimes; + long afterMod = todayTimesAfter % maxJudgeTimes; + if (beforeMod < afterMod){ + luckyer = receiver; + break; + } + } + } + + if (null != luckyer){ + break; + } + + } else { + long beforeMod = todayTimesBefore % maxJudgeTimes; + long afterMod = todayTimesAfter % maxJudgeTimes; + if (beforeMod < afterMod){ + luckyer = receiver; + break; + } } - return currentVal; // 如果当前值不等于期望值,则返回原值,不做修改 - }).intValue(); - if (result != expectedValue){ - log.error("[lucky24] extra cas failure uid {} partitionId {} lastTwoDayKey {} expectedValue {} result {}", - senderUid, partitionId, lastTwoDayCount, expectedValue, result); + + todayTimesBefore = todayTimesAfter; + } + + if (null == luckyer){ return null; } - String todayKey = String.join("_", Lucky24UserMetaService.EXTRA_POOL_COUNT, zdt.format(DateTimeUtil.dateFormatter)); - int todayAfter = userMetaMap.addAndGet(todayKey, 1).intValue(); + // cas 当天剩余额外次数 + int afterValue = userMetaMap.addAndGet(todayDayCountKey, 1).intValue(); + if (afterValue > extraPoolConfig.getDayCountLimit()){ + log.error("[lucky24] extra addAndGet fail uid {} partitionId {} todayDayKey {} afterValue {}", senderUid, partitionId, todayDayCount, afterValue); + return null; + } - log.error("[lucky24] extra cas success uid {} partitionId {} lastTwoDayKey {} expectedValue {} result {} todayKey {} todayAfter {} lucker {}", - senderUid, partitionId, lastTwoDayKey, expectedValue, result, todayKey, todayAfter, receiverList.get(0)); + log.info("[lucky24] extra addAndGet true uid {} partitionId {} todayDayKey {} afterValue {}", senderUid, partitionId, todayDayCount, afterValue); - return receiverList.get(0); + return luckyer; } - public Lucky24Record randomExtraRecord(Lucky24GiftConfig config, long senderUid, Integer partitionId, Long receiverUid, + public Lucky24Record randomExtraRecord(Lucky24GiftConfig config, Lucky24GiftConfig.Lucky24ExtraPoolConfig extraPoolConfig, long senderUid, Integer partitionId, Long receiverUid, Gift gift, int giftNum, long everyoneGoldNum, Room room, Date sendGiftTime) { - int random = RandomUtil.randomByRange(0, 10); - int drawMultiple = random < 5 ? 1000: random < 9 ? 500: 250; + + String userRechargeLevel = userRechargeLevelService.getLevelByUid(senderUid); + Lucky24GiftConfig.Lucky24ExtraPoolConfig.UserRechargeLevelJudgeConfig judgeConfig = extraPoolConfig.getUserRechargeLevelJudgeConfigMap().get(userRechargeLevel); + + RList historyQueue = userMetaService.getUserHistoryQueue(senderUid); + int historySize = historyQueue.size(); + int num = Math.min(historySize, judgeConfig.getHistoryTimes()); + List historyResultList = historyQueue.range(num); + + BigDecimal totalInput = historyResultList.stream().map(Lucky24Result::getInput).map(BigDecimal::valueOf).reduce(BigDecimal.ZERO, BigDecimal::add); + BigDecimal totalOutput = historyResultList.stream().map(Lucky24Result::getOutput).map(BigDecimal::valueOf).reduce(BigDecimal.ZERO, BigDecimal::add); + BigDecimal totalProductionRatio = totalOutput.compareTo(BigDecimal.ZERO) <= 0 || totalInput.compareTo(BigDecimal.ZERO) <= 0 ? BigDecimal.ZERO: + totalOutput.divide(totalInput, 4, RoundingMode.HALF_UP); + + //nullable + Map.Entry drawMultipleEntry = judgeConfig.getProductionRatioMultipleMap().ceilingEntry(totalProductionRatio); + int drawMultiple = drawMultipleEntry == null ? 0: drawMultipleEntry.getValue(); + + log.info("[lucky24] extra randomExtra uid {} partitionId {} totalInput {} totalOutput {} totalProductionRatio {} drawMultipleEntry {} drawMultiple {}", + senderUid, partitionId, totalInput, totalOutput, totalProductionRatio, drawMultipleEntry, drawMultiple); long afterMultiple = drawMultiple; @@ -132,8 +159,8 @@ public class Lucky24ExtraService { userMetaService.updateExtraUserMeta(senderUid, partitionId, everyoneGoldNum, winGoldNum); - log.info("[lucky24] extra uid {} partitionId {} receiverUid {} random {} drawMultiple {} preWinGoldNum {} afterMultiple {} winGoldNum {}", - senderUid, partitionId, receiverUid, random, drawMultiple, preWinGoldNum, afterMultiple, winGoldNum); + log.info("[lucky24] extra uid {} partitionId {} receiverUid {} drawMultiple {} preWinGoldNum {} afterMultiple {} winGoldNum {}", + senderUid, partitionId, receiverUid, drawMultiple, preWinGoldNum, afterMultiple, winGoldNum); return recordService.buildRecord(senderUid, partitionId, gift, giftNum, null != room? room.getUid(): null, receiverUid, Lucky24PoolTypeEnum.EXTRA_POOL.getType(), null, diff --git a/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/lucky/Lucky24UserMetaService.java b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/lucky/Lucky24UserMetaService.java index f25630a84..98d59baba 100644 --- a/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/lucky/Lucky24UserMetaService.java +++ b/accompany-business/accompany-business-service/src/main/java/com/accompany/business/service/lucky/Lucky24UserMetaService.java @@ -25,7 +25,7 @@ import java.util.Set; @Service public class Lucky24UserMetaService { - private static final String TIMES_KEY = "times"; + public static final String TIMES_KEY = "times"; public static final String INPUT_KEY = "input"; public static final String OUTPUT_KEY = "output"; @@ -181,36 +181,25 @@ public class Lucky24UserMetaService { long todayStartTimeLong = DateTimeUtil.getZonedTodayTime(partitionEnum.getZoneId()); String today = String.valueOf(todayStartTimeLong); - String todayInputKey = String.join("_", today, INPUT_KEY); - long todayInput = userMetaMap.addAndGet(todayInputKey, input).longValue(); - String todayOutputKey = String.join("_", today, OUTPUT_KEY); - long todayOutput = userMetaMap.addAndGet(todayOutputKey, output).longValue(); + String todayTimesKey = String.join("_", today, TIMES_KEY); + long todayTimes = userMetaMap.addAndGet(todayTimesKey, 1L).longValue(); long userMetaToday = userMetaMap.computeIfAbsent(TODAY, k->todayStartTimeLong).longValue(); if (userMetaToday < todayStartTimeLong && userMetaMap.replace(TODAY, userMetaToday, todayStartTimeLong)){ // 清理昨天 String oldToday = String.valueOf(userMetaToday); + String oldTodayTimesKey = String.join("_", oldToday, TIMES_KEY); String oldTodayInputKey = String.join("_", oldToday, INPUT_KEY); String oldTodayOutputKey = String.join("_", oldToday, OUTPUT_KEY); - userMetaMap.fastRemove(oldTodayInputKey, oldTodayOutputKey); - // 清理额外线计数器 - String todayExtraPoolKey = String.join("_", EXTRA_POOL_COUNT, today); - String yesterday = DateTimeUtil.getDateTimeByZoneId(partitionEnum.getZoneId()).minusDays(1L).format(DateTimeUtil.dateFormatter); - String yesterdayExtraPoolKey = String.join("_", EXTRA_POOL_COUNT, yesterday); + String oldTodayExtraPoolKey = String.join("_", oldToday, EXTRA_POOL_COUNT); - String extraPoolKeyPattern = EXTRA_POOL_COUNT + "*"; - Set extraPoolKeySet = userMetaMap.keySet(extraPoolKeyPattern); - for (String extraPoolKey : extraPoolKeySet){ - if (!extraPoolKey.equals(todayExtraPoolKey) && !extraPoolKey.equals(yesterdayExtraPoolKey)){ - userMetaMap.fastRemove(extraPoolKey); - } - } + userMetaMap.fastRemove(oldTodayTimesKey, oldTodayInputKey, oldTodayOutputKey, oldTodayExtraPoolKey); } - log.info("[Lucky24] updateUserMeta uid {} times {} today {} todayInput {} todayOutput {}", - senderUid, times, todayStartTimeLong, todayInput, todayOutput); + log.info("[Lucky24] updateUserMeta uid {} times {} today {} todayTimes {}", + senderUid, times, todayStartTimeLong, todayTimes); } public RMap getUserMeta(Long uid) {