import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
@ApolloJsonValue("${lottery.list:[{"name":"vip","code":"1001","count":"10"}]}")
private List<LotteryListVo> lotteryList;
@Resource
private BibleLotteryDao bibleLotteryDao;
@Resource
private StringRedisTemplate stringRedisTemplate;
@Resource(name = "redissonClient")
private RedissonClient redissonClient;
public void winLottery(LotteryWinRequest request, String userId, Integer count) throws BusinessException {
String code = request.getCode();
String packageName = request.getPackageName();
String redisLockKey = String.format(BibleConstant.LOTTERY_LIST_LOCK_PACKAGE_NAME, packageName, code);
String key = String.format(BibleConstant.LOTTERY_LIST_PACKAGE_NAME, packageName, code);
RLock lock = redissonClient.getLock(redisLockKey);
try {
boolean lockAcquired = lock.tryLock(100, 10000, TimeUnit.MILLISECONDS);
if (!lockAcquired) {
log.info("Lottery Win Lock not acquired redisKey", key);
throw new BusinessRuntimeException(ErrorCode.GET_REDISSON_LOCK_ERROR);
}
Long startTime = DateUtils.getCurrentTime();
String redisValue = stringRedisTemplate.opsForValue().get(key);
Integer nowAvail = 0;
if (StringUtils.isEmpty(redisValue)) {
Integer nowCount = bibleLotteryDao.selectCountByCode(packageName, code);
nowAvail = count - nowCount;
} else {
nowAvail = Integer.valueOf(redisValue);
}
boolean win = nowAvail > 0;
if (win) {
--nowAvail;
}
BibleLotteryPO bibleLotteryPO = new BibleLotteryPO();
bibleLotteryPO.setUserId(userId);
bibleLotteryPO.setClientId(request.getClientId());
bibleLotteryPO.setPackageName(request.getPackageName());
bibleLotteryPO.setCode(code);
bibleLotteryPO.setTotalCount(count);
bibleLotteryPO.setAvailableCount(nowAvail);
bibleLotteryPO.setIsWin(win ? 1 : 0);
bibleLotteryPO.setCreateTime(startTime);
bibleLotteryPO.setUpdateTime(DateUtils.getCurrentTime());
bibleLotteryDao.insert(bibleLotteryPO);
if (win) {
stringRedisTemplate.opsForValue().set(key, JSON.toJSONString(nowAvail), 1, TimeUnit.HOURS);
} else {
throw new BusinessException(ErrorCode.LOTTERY_COUNT_LIMIT);
}
} catch (InterruptedException e) {
log.error("Lottery Win Lock get InterruptedException redisKey:{},e:{}", key, e);
throw new BusinessRuntimeException(ErrorCode.GET_REDISSON_LOCK_ERROR);
} finally {
if (lock.isLocked() && lock.isHeldByCurrentThread()) {
lock.unlock();
}
log.info("Lottery Win Lock get finally unlock redisKey:{}" + key);
}
}