幸运24-额外-分充值等级取值判断

This commit is contained in:
2025-10-14 11:55:26 +08:00
parent 4cbc4a0aea
commit 77737e198e
4 changed files with 112 additions and 78 deletions

View File

@@ -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<String> userRechargeLevels;
@Deprecated
private BigDecimal todayProductionRatio;
@Deprecated
private Long todayDiff;
@Deprecated
private Integer twoDayCountLimit;
private Integer dayCountLimit;
private List<Integer> timesJudgeArray;
private Map<String, UserRechargeLevelJudgeConfig> userRechargeLevelJudgeConfigMap;
@Data
public static class UserRechargeLevelJudgeConfig{
private int historyTimes;
private TreeMap<BigDecimal, Integer> productionRatioMultipleMap;
}
}
}

View File

@@ -102,22 +102,24 @@ public class Lucky24GiftSendService {
private Map<Long, Lucky24Record> draw(Lucky24GiftConfig config, Lucky24GiftConfig partitionConfig, long senderUid, Integer partitionId,
Gift gift, int everyGiftNum, long everyoneGoldNum,
List<Long> 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<Long> receiverUidList = new ArrayList<>(receiverList);
receiverUidList.remove(extraLucker);
receiverUidList.remove(extraLuckerUid);
Map<Long, Lucky24Record> recordMap = draw(config, partitionConfig, senderUid, partitionId, gift, everyGiftNum, everyoneGoldNum, receiverUidList, room, sendGiftTime);
recordMap.put(extraLucker, extraRecord);
recordMap.put(extraLuckerUid, extraRecord);
return recordMap;
}

View File

@@ -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<Long> receiverList) {
public Long selectExtraLucker(Lucky24GiftConfig.Lucky24ExtraPoolConfig extraPoolConfig, long senderUid, Integer partitionId, List<Long> 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<String, Number> userMetaMap = userMetaService.getUserMeta(senderUid);
Map<String, Number> 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<Integer> 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<Lucky24Result> historyQueue = userMetaService.getUserHistoryQueue(senderUid);
int historySize = historyQueue.size();
int num = Math.min(historySize, judgeConfig.getHistoryTimes());
List<Lucky24Result> 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<BigDecimal, Integer> 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,

View File

@@ -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<String> 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<String, Number> getUserMeta(Long uid) {