幸运25-poolJudge
This commit is contained in:
@@ -9,21 +9,34 @@ import java.util.Map;
|
||||
@Data
|
||||
public class Lucky25GiftConfig {
|
||||
|
||||
private BigDecimal platformRatio;
|
||||
private BigDecimal receiverRatio;
|
||||
//n
|
||||
private BigDecimal productionRatio_N;
|
||||
|
||||
private Map<Integer, Lucky25GiftConfig> ratioPartitionMap;
|
||||
|
||||
private BigDecimal platformRatio;
|
||||
private BigDecimal receiverRatio;
|
||||
|
||||
//
|
||||
private Integer poolSize = 500;
|
||||
private Integer newUserPoolCount = 0;
|
||||
|
||||
//n
|
||||
private BigDecimal productionRatio_N;
|
||||
|
||||
private BigDecimal todayInput;
|
||||
private BigDecimal todayProductionRatio;
|
||||
|
||||
//
|
||||
private Long highRechargeThreshold_M;
|
||||
|
||||
//
|
||||
private Long judgeInputThreshold;
|
||||
|
||||
private BigDecimal highPoolEntreProductionRatio;
|
||||
private BigDecimal highPoolQuitProductionRatio;
|
||||
|
||||
private BigDecimal lowPoolEntreProductionRatio;
|
||||
private BigDecimal lowPoolQuitProductionRatio;
|
||||
|
||||
//
|
||||
private Integer specialTipMulti;
|
||||
|
||||
private Long allRoomChatToastValue;
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package com.accompany.business.service.gift;
|
||||
|
||||
import com.accompany.business.constant.Lucky25PoolTypeEnum;
|
||||
import com.accompany.business.dto.lucky.Lucky25GiftConfig;
|
||||
import com.accompany.business.dto.lucky.Lucky25Result;
|
||||
import com.accompany.business.model.Gift;
|
||||
@@ -31,6 +32,8 @@ public class Lucky25DrawService {
|
||||
@Autowired
|
||||
private Lucky25HighRechargePoolService highRechargePoolService;
|
||||
@Autowired
|
||||
private Lucky25PoolJudgeService poolJudgeService;
|
||||
@Autowired
|
||||
private Lucky25RecordService recordService;
|
||||
@Autowired
|
||||
private Lucky25SettlementService settlementService;
|
||||
@@ -46,9 +49,10 @@ public class Lucky25DrawService {
|
||||
long totalGoldNum = everyoneGoldNum * receiverList.size();
|
||||
RMap<String, Number> userMetaMap = userMetaService.getUserMeta(senderUid);
|
||||
long afterTotalInput = userMetaMap.addAndGet(Lucky25UserMetaService.INPUT_KEY, totalGoldNum).longValue();
|
||||
long beforeTotalInput = afterTotalInput - totalGoldNum;
|
||||
|
||||
Lucky25Result highRechargeResult = drawHighRechargeUserPool(config, senderUid, partitionId,
|
||||
totalGoldNum, afterTotalInput);
|
||||
beforeTotalInput, afterTotalInput);
|
||||
if (null != highRechargeResult){
|
||||
Long receiver = receiverList.remove(0);
|
||||
highRechargeResult.setReceiverUid(receiver);
|
||||
@@ -83,6 +87,10 @@ public class Lucky25DrawService {
|
||||
}
|
||||
|
||||
// todo 比较
|
||||
if (null != config.getJudgeInputThreshold() && beforeTotalInput > config.getJudgeInputThreshold()){
|
||||
int curPoolType = userMetaMap.getOrDefault(Lucky25UserMetaService.POOL_TYPE, Lucky25PoolTypeEnum.NEW_USER_POOL.getType()).intValue();
|
||||
poolJudgeService.judge(config, senderUid, partitionId, curPoolType);
|
||||
}
|
||||
|
||||
|
||||
// todo 原数组
|
||||
@@ -93,13 +101,15 @@ public class Lucky25DrawService {
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private Lucky25Result drawHighRechargeUserPool(Lucky25GiftConfig config, long uid, int partitionId, long totalGoldNum, long afterInput) {
|
||||
private Lucky25Result drawHighRechargeUserPool(Lucky25GiftConfig config, long uid, int partitionId, long beforeInput, long afterInput) {
|
||||
Lucky25GiftConfig partitionConfig = config.getRatioByPartitionId(partitionId);
|
||||
if (null == partitionConfig || null == partitionConfig.getHighRechargeThreshold_M()){
|
||||
return null;
|
||||
}
|
||||
|
||||
long beforeInput = afterInput - totalGoldNum;
|
||||
if (beforeInput <= 0L){
|
||||
return null;
|
||||
}
|
||||
long beforeThreshold = beforeInput / partitionConfig.getHighRechargeThreshold_M();
|
||||
long afterThreshold = afterInput / partitionConfig.getHighRechargeThreshold_M();
|
||||
if (beforeThreshold >= afterThreshold){
|
||||
|
@@ -0,0 +1,77 @@
|
||||
package com.accompany.business.service.gift;
|
||||
|
||||
import com.accompany.business.constant.Lucky25PoolTypeEnum;
|
||||
import com.accompany.business.dto.lucky.Lucky25GiftConfig;
|
||||
import com.accompany.business.service.lucky.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class Lucky25PoolJudgeService {
|
||||
|
||||
@Autowired
|
||||
private Lucky25UserMetaService userMetaService;
|
||||
@Autowired
|
||||
private Lucky25PoolService poolService;
|
||||
|
||||
public void judge(Lucky25GiftConfig config, Long senderUid, int partitionId, int curPoolType) {
|
||||
if (curPoolType == Lucky25PoolTypeEnum.NEW_USER_POOL.getType()
|
||||
|| curPoolType == Lucky25PoolTypeEnum.BLACK_POOL.getType()){
|
||||
return;
|
||||
}
|
||||
|
||||
Lucky25GiftConfig partitionConfig = config.getRatioByPartitionId(partitionId);
|
||||
|
||||
BigDecimal judgeProductionRatio = userMetaService.getUserJudgeProductionRatio(senderUid, config.getJudgeInputThreshold());
|
||||
if (curPoolType == Lucky25PoolTypeEnum.NORMAL_POOL.getType()){
|
||||
if (null != partitionConfig.getHighPoolEntreProductionRatio() && judgeProductionRatio.compareTo(partitionConfig.getHighPoolEntreProductionRatio()) < 0){
|
||||
if (!userMetaService.casCurPoolType(senderUid, curPoolType, Lucky25PoolTypeEnum.HIGH_POOL.getType())){
|
||||
//todo log failure
|
||||
return;
|
||||
}
|
||||
poolService.delPoolAndGenPool(config, senderUid, Lucky25PoolTypeEnum.HIGH_POOL.getType());
|
||||
return;
|
||||
} else if (null != partitionConfig.getLowPoolEntreProductionRatio() && judgeProductionRatio.compareTo(partitionConfig.getLowPoolEntreProductionRatio()) > 0) {
|
||||
if (!userMetaService.casCurPoolType(senderUid, curPoolType, Lucky25PoolTypeEnum.LOW_POOL.getType())){
|
||||
//todo log failure
|
||||
return;
|
||||
}
|
||||
poolService.delPoolAndGenPool(config, senderUid, Lucky25PoolTypeEnum.LOW_POOL.getType());
|
||||
return;
|
||||
}
|
||||
|
||||
//todo log
|
||||
|
||||
} else if (curPoolType == Lucky25PoolTypeEnum.HIGH_POOL.getType()) {
|
||||
|
||||
if (null != partitionConfig.getHighPoolQuitProductionRatio() && judgeProductionRatio.compareTo(partitionConfig.getHighPoolQuitProductionRatio()) > 0){
|
||||
if (!userMetaService.casCurPoolType(senderUid, curPoolType, Lucky25PoolTypeEnum.NEW_USER_POOL.getType())){
|
||||
//todo log failure
|
||||
return;
|
||||
}
|
||||
poolService.delPoolAndGenPool(config, senderUid, Lucky25PoolTypeEnum.NEW_USER_POOL.getType(), 4);
|
||||
return;
|
||||
}
|
||||
|
||||
//todo log
|
||||
|
||||
} else if (curPoolType == Lucky25PoolTypeEnum.LOW_POOL.getType()) {
|
||||
|
||||
if (null != partitionConfig.getLowPoolQuitProductionRatio() && judgeProductionRatio.compareTo(partitionConfig.getLowPoolQuitProductionRatio()) < 0){
|
||||
if (!userMetaService.casCurPoolType(senderUid, curPoolType, Lucky25PoolTypeEnum.HIGH_POOL.getType())){
|
||||
//todo log failure
|
||||
return;
|
||||
}
|
||||
poolService.delPoolAndGenPool(config, senderUid, Lucky25PoolTypeEnum.NEW_USER_POOL.getType(), 4);
|
||||
return;
|
||||
}
|
||||
|
||||
//todo log
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@@ -50,6 +50,57 @@ public class Lucky25PoolService {
|
||||
throw new ServiceException(BusiStatus.SERVERBUSY);
|
||||
}
|
||||
|
||||
public void delPoolAndGenPool(Lucky25GiftConfig config, Long uid, int poolType){
|
||||
delPoolAndGenPool(config, uid, poolType, 1);
|
||||
}
|
||||
|
||||
public void delPoolAndGenPool(Lucky25GiftConfig config, Long uid, int poolType, int genNum){
|
||||
RQueue<Lucky25Result> userPool = getUserPool(uid);
|
||||
userPool.clear();
|
||||
genRandomPoolByType(config, uid, userPool, poolType, genNum);
|
||||
}
|
||||
|
||||
private void genRandomPoolByType(Lucky25GiftConfig config, Long uid, RQueue<Lucky25Result> userPool,
|
||||
Integer pooType, int genNum) {
|
||||
boolean locked = false;
|
||||
RLock lock = redissonClient.getLock(RedisKey.lucky_25_user_lock.getKey(uid.toString()));
|
||||
try {
|
||||
locked = lock.tryLock(5,3, TimeUnit.SECONDS);
|
||||
|
||||
if (!userPool.isEmpty()){
|
||||
log.info("[lucky25] genRandomPoolByType uid {} 已生成pool,无需再生成", uid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!locked) {
|
||||
throw new ServiceException(BusiStatus.SERVERBUSY);
|
||||
}
|
||||
|
||||
Lucky25PoolTypeEnum poolType = Lucky25PoolTypeEnum.get(pooType);
|
||||
|
||||
List<Lucky25Pool> poolList = poolMapper.selectList(null);
|
||||
if (CollectionUtils.isEmpty(poolList)){
|
||||
throw new ServiceException(BusiStatus.SEIZE_TREASURE_POOL_CONFIG_ERROR);
|
||||
}
|
||||
|
||||
for (int i = 0; i < genNum; i++) {
|
||||
int randomIndex = RandomUtil.randomByRange(0, poolList.size());
|
||||
Lucky25Pool randomPool = poolList.get(randomIndex);
|
||||
log.info("[lucky25] genRandomPoolByType selectPool type {}, index {}, pooList {}, randomIndex {}, expect {}",
|
||||
poolType, i, JSON.toJSONString(poolList.stream().map(Lucky25Pool::getExpect).collect(Collectors.toList())), randomIndex, randomPool.getExpect());
|
||||
|
||||
buildPool(config, uid, userPool, randomPool);
|
||||
}
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
if (locked) {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void genPool(Lucky25GiftConfig config, Long uid, int partitionId, RQueue<Lucky25Result> userPool) {
|
||||
boolean locked = false;
|
||||
RLock lock = redissonClient.getLock(RedisKey.lucky_25_user_lock.getKey(uid.toString()));
|
||||
|
@@ -16,6 +16,7 @@ import java.math.RoundingMode;
|
||||
import java.time.Duration;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@@ -25,13 +26,13 @@ public class Lucky25UserMetaService {
|
||||
public static final String INPUT_KEY = "input";
|
||||
public static final String OUTPUT_KEY = "output";
|
||||
|
||||
private static final String POOL_TYPE = "pool_type";
|
||||
public static final String POOL_TYPE = "pool_type";
|
||||
|
||||
private static final String TODAY = "today";
|
||||
|
||||
public static final String ADMIN_1000_NUM_KEY = "admin_1000_num";
|
||||
|
||||
private static final BigDecimal HISTORY_QUEUE_INPUT_MAX = BigDecimal.valueOf(100000L);
|
||||
private final int HISTORY_MIN_SIZE = 2000;
|
||||
|
||||
@Autowired
|
||||
private RedissonClient redissonClient;
|
||||
@@ -40,6 +41,53 @@ public class Lucky25UserMetaService {
|
||||
return getUserMeta(uid).getOrDefault(TIMES_KEY, 0L).longValue();
|
||||
}
|
||||
|
||||
public boolean casCurPoolType(long uid, Integer beforePoolType, Integer afterPoolType){
|
||||
Number result = getUserMeta(uid).computeIfPresent(POOL_TYPE, (key, value)-> value.equals(beforePoolType)? afterPoolType: value);
|
||||
boolean success = !Objects.equals(result, beforePoolType);
|
||||
if (success){
|
||||
//todo log
|
||||
} else {
|
||||
//todo log failure
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
public BigDecimal getUserJudgeProductionRatio(Long uid, Long judgeInputThreshold) {
|
||||
RList<Lucky25Result> historyQueue = getUserHistoryQueue(uid);
|
||||
List<Lucky25Result> historyResult = historyQueue.readAll();
|
||||
int historySize = historyResult.size();
|
||||
|
||||
int index = 0;
|
||||
long historyInput = 0L;
|
||||
long historyOutput = 0L;
|
||||
for (Lucky25Result result : historyResult){
|
||||
index++;
|
||||
historyInput += result.getInput();
|
||||
historyOutput += result.getOutput();
|
||||
|
||||
if (historyInput >= judgeInputThreshold){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BigDecimal historyInputB = BigDecimal.valueOf(historyInput);
|
||||
BigDecimal historyOutputB = BigDecimal.valueOf(historyOutput);
|
||||
|
||||
BigDecimal productionRatio = historyOutputB.compareTo(BigDecimal.ZERO) > 0 ?
|
||||
historyOutputB.divide(historyInputB,4, RoundingMode.HALF_UP): BigDecimal.ZERO;
|
||||
log.info("[lucky25] userJudgeProductionRation uid {}, historyInput {}, historyOutput {}, num {}, productionRatio {}",
|
||||
uid, historyInput, historyOutput, index, productionRatio);
|
||||
|
||||
if (index >= historySize || HISTORY_MIN_SIZE >= historySize){
|
||||
return productionRatio;
|
||||
}
|
||||
|
||||
int len = Math.max(index, HISTORY_MIN_SIZE-1);
|
||||
historyQueue.trimAsync(0, len);
|
||||
|
||||
return productionRatio;
|
||||
}
|
||||
|
||||
public BigDecimal getUserLast2000ProductionRatio(Long uid) {
|
||||
RList<Lucky25Result> historyQueue = getUserHistoryQueue(uid);
|
||||
//保留2000条记录
|
||||
@@ -51,7 +99,7 @@ public class Lucky25UserMetaService {
|
||||
BigDecimal historyOutputB = BigDecimal.valueOf(historyOutput);
|
||||
|
||||
BigDecimal productionRatio = historyOutputB.compareTo(BigDecimal.ZERO) > 0 ?
|
||||
historyOutputB.divide(historyInputB,2, RoundingMode.HALF_UP): BigDecimal.ZERO;
|
||||
historyOutputB.divide(historyInputB,4, RoundingMode.HALF_UP): BigDecimal.ZERO;
|
||||
log.info("[lucky25] buildPool last2000 uid {}, historyInput {}, historyOutput {}, num {}, productionRatio {}",
|
||||
uid, historyInput, historyOutput, num, productionRatio);
|
||||
return productionRatio;
|
||||
@@ -61,7 +109,7 @@ public class Lucky25UserMetaService {
|
||||
RMap<String, Number> userMetaMap = getUserMeta(uid);
|
||||
BigDecimal output = BigDecimal.valueOf(userMetaMap.getOrDefault(OUTPUT_KEY, 0L).longValue());
|
||||
BigDecimal input = BigDecimal.valueOf(userMetaMap.getOrDefault(INPUT_KEY, 0L).longValue());
|
||||
BigDecimal productionRatio = BigDecimal.ZERO.equals(output)? BigDecimal.ZERO: output.divide(input,2,RoundingMode.HALF_UP);
|
||||
BigDecimal productionRatio = BigDecimal.ZERO.equals(output)? BigDecimal.ZERO: output.divide(input,4,RoundingMode.HALF_UP);
|
||||
log.info("[lucky25] buildPool total uid {}, totalOutput {}, totalInput {}, productionRatio {}",
|
||||
uid, output, input, productionRatio);
|
||||
return productionRatio;
|
||||
|
Reference in New Issue
Block a user