秘地新的需求池更新版本-需求更改
This commit is contained in:
@@ -37,98 +37,116 @@ class BlindBoxTurntableGiftDrawWorld extends Model
|
||||
public function draw_gift($gift_bag_id, $user_id, $gift_user_ids, $num = 1, $room_id = 0, $heart_id = 0,$auction_id = 0)
|
||||
{
|
||||
// 最大重试次数
|
||||
$maxRetries = 3;
|
||||
for ($attempt = 0; $attempt < $maxRetries; $attempt++) {
|
||||
try {
|
||||
// 1. 验证参数并提前处理错误
|
||||
$validationResult = $this->validateDrawParameters($gift_bag_id, $user_id, $gift_user_ids);
|
||||
if ($validationResult !== true) {
|
||||
return $validationResult;
|
||||
}
|
||||
// 2. 预加载必要数据
|
||||
$loadResult = $this->loadDrawData($gift_bag_id, $user_id, $room_id, $num, $gift_user_ids);
|
||||
if ($loadResult['code'] !== 1) {
|
||||
return $loadResult;
|
||||
}
|
||||
// 添加以下检查以防止 null 错误
|
||||
if (!isset($loadResult['data']) || !is_array($loadResult['data'])) {
|
||||
return ['code' => 0, 'msg' => '数据加载失败', 'data' => null];
|
||||
}
|
||||
['bag_data' => $bag_data, 'room' => $room, 'xlh_ext' => $xlh_ext] = $loadResult['data'];
|
||||
try {
|
||||
// 1. 验证参数并提前处理错误
|
||||
$validationResult = $this->validateDrawParameters($gift_bag_id, $user_id, $gift_user_ids);
|
||||
if ($validationResult !== true) {
|
||||
return $validationResult;
|
||||
}
|
||||
// 2. 预加载必要数据
|
||||
$loadResult = $this->loadDrawData($gift_bag_id, $user_id, $room_id, $num, $gift_user_ids);
|
||||
if ($loadResult['code'] !== 1) {
|
||||
return $loadResult;
|
||||
}
|
||||
// 添加以下检查以防止 null 错误
|
||||
if (!isset($loadResult['data']) || !is_array($loadResult['data'])) {
|
||||
return ['code' => 0, 'msg' => '数据加载失败', 'data' => null];
|
||||
}
|
||||
['bag_data' => $bag_data, 'room' => $room, 'xlh_ext' => $xlh_ext] = $loadResult['data'];
|
||||
|
||||
// 3. 预计算抽奖结果
|
||||
$precomputeResult = $this->precomputeDrawResults(
|
||||
$bag_data,
|
||||
$gift_user_ids,
|
||||
$num
|
||||
);
|
||||
if ($precomputeResult['code'] !== 1) {
|
||||
return $precomputeResult;
|
||||
// 3. 预计算抽奖结果
|
||||
$precomputeResult = $this->precomputeDrawResults(
|
||||
$bag_data,
|
||||
$gift_user_ids,
|
||||
$num
|
||||
);
|
||||
if ($precomputeResult['code'] !== 1) {
|
||||
return $precomputeResult;
|
||||
}
|
||||
$precomputedResults = $precomputeResult['data']['results'];
|
||||
$availableGiftss = $precomputeResult['data']['availableGifts'];
|
||||
$currentXlhPeriodsNum = $precomputeResult['data']['current_xlh_periods_num'];
|
||||
$addcurrentXlhPeriodsNum = $precomputeResult['data']['addcurrentXlhPeriodsNum'];
|
||||
$expectedCount = count(explode(',', $gift_user_ids)) * $num;
|
||||
if (count($precomputedResults) != $expectedCount) {
|
||||
// 记录错误到Redis
|
||||
$this->recordDrawErrorToRedis($expectedCount, count($precomputedResults), $room_id, $user_id, $gift_bag_id, $num, $gift_user_ids, $precomputedResults);
|
||||
return ['code' => 0, 'msg' => '网络加载失败,请重试!', 'data' => null];
|
||||
}
|
||||
foreach ($precomputedResults as $result) {
|
||||
$key = $result['gift_user_id'] . '_' . $result['gift_bag_detail']['foreign_id'];
|
||||
if (!isset($giftUserCountsJianCha[$key])) {
|
||||
$giftUserCountsJianCha[$key] = [
|
||||
'gift_user_id' => $result['gift_user_id'],
|
||||
'gift_id' => $result['gift_bag_detail']['foreign_id'],
|
||||
'count' => 0,
|
||||
'gift_price' => $result['gift']['gift_price'],
|
||||
'quantity' => $result['gift_bag_detail']['quantity'],
|
||||
];
|
||||
}
|
||||
$precomputedResults = $precomputeResult['data']['results'];
|
||||
$availableGiftss = $precomputeResult['data']['availableGifts'];
|
||||
$currentXlhPeriodsNum = $precomputeResult['data']['current_xlh_periods_num'];
|
||||
$addcurrentXlhPeriodsNum = $precomputeResult['data']['addcurrentXlhPeriodsNum'];
|
||||
$expectedCount = count(explode(',', $gift_user_ids)) * $num;
|
||||
if (count($precomputedResults) != $expectedCount) {
|
||||
$giftUserCountsJianCha[$key]['count']++;
|
||||
if($giftUserCountsJianCha[$key]['count'] > $result['gift_bag_detail']['quantity']){
|
||||
// 记录错误到Redis
|
||||
$this->recordDrawErrorToRedis($expectedCount, count($precomputedResults), $room_id, $user_id, $gift_bag_id, $num, $gift_user_ids, $precomputedResults);
|
||||
// 使用正确的Redis方法存储数据
|
||||
$key = 'blind_box_draw_world_errors_' . date('Y-m-d-H-i-s');
|
||||
$errorData = [
|
||||
'gift_bag_id' => $gift_bag_id,
|
||||
'user_id' => $user_id,
|
||||
'gift_user_ids' => $gift_user_ids,
|
||||
'num' => $num,
|
||||
'giftUserCountsJianCha' => $giftUserCountsJianCha,
|
||||
];
|
||||
$this->redis->setex($key, 86400 * 7, "礼物数量超出限制 ".json_encode($errorData));
|
||||
return ['code' => 0, 'msg' => '网络加载失败,请重试!', 'data' => null];
|
||||
}
|
||||
// 4. 执行抽奖事务(核心操作)
|
||||
$transactionResult = $this->executeDrawTransaction(
|
||||
$bag_data,
|
||||
$user_id,
|
||||
$room_id,
|
||||
$num,
|
||||
$precomputedResults,
|
||||
$availableGiftss,
|
||||
$gift_user_ids,
|
||||
$heart_id,
|
||||
$auction_id
|
||||
);
|
||||
if ($transactionResult['code'] !== 1) {
|
||||
return $transactionResult;
|
||||
}
|
||||
$boxTurntableLog = $transactionResult['data']['log_id'];
|
||||
$giftCounts = $transactionResult['data']['gift_counts'];
|
||||
|
||||
// 5. 处理后续操作(非事务性操作)
|
||||
$this->handlePostDrawOperations(
|
||||
$precomputedResults,
|
||||
$boxTurntableLog,
|
||||
$room_id,
|
||||
$xlh_ext,
|
||||
$currentXlhPeriodsNum,
|
||||
$addcurrentXlhPeriodsNum,
|
||||
$room
|
||||
);
|
||||
|
||||
// 6. 构建并返回结果
|
||||
return $this->buildDrawResult($boxTurntableLog, $giftCounts);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$key = 'blind_box_draw_errors_' . date('Y-m-d-H-i-s');
|
||||
$errorData = [
|
||||
'gift_bag_id' => $gift_bag_id,
|
||||
'user_id' => $user_id,
|
||||
'gift_user_ids' => $gift_user_ids,
|
||||
'num' => $num,
|
||||
'room_id' => $room_id,
|
||||
'heart_id' => $heart_id,
|
||||
'auction_id' => $auction_id,
|
||||
];
|
||||
if ($this->redis) {
|
||||
$this->redis->setex($key, 86400 * 7, $e->getMessage() . ' ' . json_encode($errorData));
|
||||
}
|
||||
// 如果是死锁且还有重试机会
|
||||
if (strpos($e->getMessage(), 'Deadlock') !== false && $attempt < $maxRetries - 1) {
|
||||
// 随机延迟后重试
|
||||
usleep(rand(50000, 200000)); // 50-200ms
|
||||
continue;
|
||||
}
|
||||
return ['code' => 0, 'msg' => "网络加载失败,请重试!", 'data' => null];
|
||||
}
|
||||
// 4. 执行抽奖事务(核心操作)
|
||||
$transactionResult = $this->executeDrawTransaction(
|
||||
$bag_data,
|
||||
$user_id,
|
||||
$room_id,
|
||||
$num,
|
||||
$precomputedResults,
|
||||
$availableGiftss,
|
||||
$gift_user_ids,
|
||||
$heart_id,
|
||||
$auction_id
|
||||
);
|
||||
if ($transactionResult['code'] !== 1) {
|
||||
return $transactionResult;
|
||||
}
|
||||
$boxTurntableLog = $transactionResult['data']['log_id'];
|
||||
$giftCounts = $transactionResult['data']['gift_counts'];
|
||||
|
||||
// 5. 处理后续操作(非事务性操作)
|
||||
$this->handlePostDrawOperations(
|
||||
$precomputedResults,
|
||||
$boxTurntableLog,
|
||||
$room_id,
|
||||
$xlh_ext,
|
||||
$currentXlhPeriodsNum,
|
||||
$addcurrentXlhPeriodsNum,
|
||||
$room
|
||||
);
|
||||
|
||||
// 6. 构建并返回结果
|
||||
return $this->buildDrawResult($boxTurntableLog, $giftCounts);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$key = 'blind_box_draw_errors_' . date('Y-m-d-H-i-s');
|
||||
$errorData = [
|
||||
'gift_bag_id' => $gift_bag_id,
|
||||
'user_id' => $user_id,
|
||||
'gift_user_ids' => $gift_user_ids,
|
||||
'num' => $num,
|
||||
'room_id' => $room_id,
|
||||
'heart_id' => $heart_id,
|
||||
'auction_id' => $auction_id,
|
||||
];
|
||||
if ($this->redis) {
|
||||
$this->redis->setex($key, 86400 * 7, $e->getMessage() . ' ' . json_encode($errorData));
|
||||
}
|
||||
return ['code' => 0, 'msg' => "网络加载失败,请重试!", 'data' => null];
|
||||
}
|
||||
}
|
||||
/**
|
||||
@@ -495,65 +513,55 @@ class BlindBoxTurntableGiftDrawWorld extends Model
|
||||
$bagGiftPrice = $bag_data['gift_price'] * $num * $gift_user_num;
|
||||
|
||||
// 增加重试机制
|
||||
$maxRetries = 3;
|
||||
for ($retry = 0; $retry < $maxRetries; $retry++) {
|
||||
try {
|
||||
db::startTrans();
|
||||
// 按照固定顺序处理事务步骤
|
||||
// 1. 扣除用户金币(优先处理)
|
||||
$this->deductUserCoins($user_id, $bagGiftPrice, $room_id);
|
||||
try {
|
||||
db::startTrans();
|
||||
// 按照固定顺序处理事务步骤
|
||||
// 1. 扣除用户金币(优先处理)
|
||||
$this->deductUserCoins($user_id, $bagGiftPrice, $room_id);
|
||||
|
||||
// 2. 创建抽奖记录
|
||||
$boxTurntableLog = db::name('vs_blind_box_turntable_log')->insertGetId([
|
||||
'user_id' => $user_id,
|
||||
'gift_bag_id' => $bag_data['id'],
|
||||
'num' => $num,
|
||||
'room_id' => $room_id,
|
||||
'bag_price' => $bag_data['gift_price'],
|
||||
'createtime' => time()
|
||||
]);
|
||||
// 2. 创建抽奖记录
|
||||
$boxTurntableLog = db::name('vs_blind_box_turntable_log')->insertGetId([
|
||||
'user_id' => $user_id,
|
||||
'gift_bag_id' => $bag_data['id'],
|
||||
'num' => $num,
|
||||
'room_id' => $room_id,
|
||||
'bag_price' => $bag_data['gift_price'],
|
||||
'createtime' => time()
|
||||
]);
|
||||
|
||||
if (!$boxTurntableLog) {
|
||||
throw new \Exception('添加盲盒转盘记录失败');
|
||||
}
|
||||
|
||||
// 3. 批量更新库存(按ID排序避免死锁)
|
||||
$this->batchUpdateGiftInventory($availableGiftss, $room_id);
|
||||
|
||||
// 4. 批量插入礼包发放记录
|
||||
$this->batchInsertGiftBagReceiveLog($user_id, $boxTurntableLog, $bag_data, $room_id, $precomputedResults);
|
||||
|
||||
// 5. 发送礼物
|
||||
$result = $this->sendGiftsToRecipients($precomputedResults, $room_id,$user_id,$heart_id,$auction_id);
|
||||
if (isset($result['code']) && $result['code'] !== 1) {
|
||||
throw new \Exception($result['msg']);
|
||||
}
|
||||
|
||||
db::commit();
|
||||
|
||||
// 统计礼物数量
|
||||
$giftCounts = $this->countGifts($precomputedResults);
|
||||
|
||||
return [
|
||||
'code' => 1,
|
||||
'msg' => '事务执行成功',
|
||||
'data' => [
|
||||
'log_id' => $boxTurntableLog,
|
||||
'gift_counts' => $giftCounts
|
||||
]
|
||||
];
|
||||
} catch (\Exception $e) {
|
||||
db::rollback();
|
||||
// 检查是否是死锁错误
|
||||
if (strpos($e->getMessage(), 'Deadlock') !== false && $retry < $maxRetries - 1) {
|
||||
// 等待随机时间后重试
|
||||
usleep(rand(10000, 100000)); // 10-100ms
|
||||
continue;
|
||||
}
|
||||
return ['code' => 0, 'msg' => $e->getMessage(), 'data' => null];
|
||||
if (!$boxTurntableLog) {
|
||||
throw new \Exception('添加盲盒转盘记录失败');
|
||||
}
|
||||
|
||||
// 3. 批量更新库存(按ID排序避免死锁)
|
||||
$this->batchUpdateGiftInventory($availableGiftss, $room_id);
|
||||
|
||||
// 4. 批量插入礼包发放记录
|
||||
$this->batchInsertGiftBagReceiveLog($user_id, $boxTurntableLog, $bag_data, $room_id, $precomputedResults);
|
||||
|
||||
// 5. 发送礼物
|
||||
$result = $this->sendGiftsToRecipients($precomputedResults, $room_id,$user_id,$heart_id,$auction_id);
|
||||
if (isset($result['code']) && $result['code'] !== 1) {
|
||||
throw new \Exception($result['msg']);
|
||||
}
|
||||
|
||||
db::commit();
|
||||
|
||||
// 统计礼物数量
|
||||
$giftCounts = $this->countGifts($precomputedResults);
|
||||
|
||||
return [
|
||||
'code' => 1,
|
||||
'msg' => '事务执行成功',
|
||||
'data' => [
|
||||
'log_id' => $boxTurntableLog,
|
||||
'gift_counts' => $giftCounts
|
||||
]
|
||||
];
|
||||
} catch (\Exception $e) {
|
||||
db::rollback();
|
||||
return ['code' => 0, 'msg' => $e->getMessage(), 'data' => null];
|
||||
}
|
||||
return ['code' => 0, 'msg' => '操作超时,请重试', 'data' => null];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -692,7 +700,6 @@ class BlindBoxTurntableGiftDrawWorld extends Model
|
||||
}
|
||||
$giftUserCounts[$key]['count']++;
|
||||
}
|
||||
|
||||
// 批量插入
|
||||
$batchInsertData = [];
|
||||
foreach ($giftUserCounts as $userGift) {
|
||||
|
||||
Reference in New Issue
Block a user