优化游戏实时对局页面样式
This commit is contained in:
@@ -52,23 +52,102 @@ final class GameLiveService
|
||||
if ($recordId <= 0) {
|
||||
return;
|
||||
}
|
||||
$status = (int) ($row['status'] ?? 0);
|
||||
$resultNumber = isset($row['result_number']) ? (int) $row['result_number'] : 0;
|
||||
if ($resultNumber > 0 && in_array($status, [0, 1, 2, 3], true)) {
|
||||
self::recoverPayoutForRecordOnStartup($recordId);
|
||||
return;
|
||||
}
|
||||
|
||||
$periodStartAt = (int) ($row['period_start_at'] ?? 0);
|
||||
if ($periodStartAt <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$periodSeconds = self::getConfigInt(self::KEY_PERIOD_SECONDS, 30);
|
||||
$timeoutAt = $periodStartAt + $periodSeconds + self::PAYOUT_GRACE_SECONDS + self::STARTUP_RECOVER_GRACE_SECONDS;
|
||||
if (time() <= $timeoutAt) {
|
||||
return;
|
||||
}
|
||||
self::markAbnormalAndRefundOnStartup($recordId, $status);
|
||||
}
|
||||
|
||||
$status = (int) ($row['status'] ?? 0);
|
||||
private static function recoverPayoutForRecordOnStartup(int $recordId): void
|
||||
{
|
||||
$lock = GameHotDataLock::tryAcquireWithWait(GameHotDataLock::TYPE_GAME_RECORD, (string) $recordId, 3000);
|
||||
if (!$lock['acquired']) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
$row = Db::name('game_record')->where('id', $recordId)->find();
|
||||
if (!$row) {
|
||||
return;
|
||||
}
|
||||
$status = (int) ($row['status'] ?? 0);
|
||||
if (!in_array($status, [0, 1, 2, 3], true)) {
|
||||
return;
|
||||
}
|
||||
$resultNumber = isset($row['result_number']) ? (int) $row['result_number'] : 0;
|
||||
if ($resultNumber <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$now = time();
|
||||
$payoutUntil = isset($row['payout_until']) ? (int) $row['payout_until'] : 0;
|
||||
Db::startTrans();
|
||||
try {
|
||||
GameBetSettleService::settleBetsForDraw($recordId, $resultNumber);
|
||||
if ($status === 2) {
|
||||
if ($payoutUntil <= 0) {
|
||||
$payoutUntil = $now + self::PAYOUT_GRACE_SECONDS;
|
||||
}
|
||||
Db::name('game_record')->where('id', $recordId)->update([
|
||||
'status' => 3,
|
||||
'payout_until' => $payoutUntil,
|
||||
'update_time' => $now,
|
||||
]);
|
||||
} elseif ($status === 3) {
|
||||
if ($payoutUntil <= 0) {
|
||||
$payoutUntil = $now;
|
||||
Db::name('game_record')->where('id', $recordId)->update([
|
||||
'payout_until' => $payoutUntil,
|
||||
'update_time' => $now,
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
$payoutUntil = $now;
|
||||
Db::name('game_record')->where('id', $recordId)->update([
|
||||
'status' => 3,
|
||||
'payout_until' => $payoutUntil,
|
||||
'update_time' => $now,
|
||||
]);
|
||||
}
|
||||
Db::commit();
|
||||
} catch (Throwable $e) {
|
||||
Db::rollback();
|
||||
Log::warning('game live startup payout recover failed', [
|
||||
'record_id' => $recordId,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
GameHotDataCoordinator::afterGameRecordCommitted($recordId);
|
||||
self::publishSnapshot(null);
|
||||
|
||||
if ($payoutUntil <= $now) {
|
||||
self::finalizePayoutForRecordLocked($recordId);
|
||||
}
|
||||
} finally {
|
||||
GameHotDataLock::release(GameHotDataLock::TYPE_GAME_RECORD, (string) $recordId, $lock['token'], $lock['redis_lock']);
|
||||
}
|
||||
}
|
||||
|
||||
private static function markAbnormalAndRefundOnStartup(int $recordId, int $status): void
|
||||
{
|
||||
$lock = GameHotDataLock::tryAcquireWithWait(GameHotDataLock::TYPE_GAME_RECORD, (string) $recordId, 3000);
|
||||
if (!$lock['acquired']) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
$fresh = Db::name('game_record')->where('id', $recordId)->find();
|
||||
if (!$fresh) {
|
||||
@@ -78,12 +157,8 @@ final class GameLiveService
|
||||
if (!in_array($freshStatus, [0, 1, 2, 3], true)) {
|
||||
return;
|
||||
}
|
||||
$freshPeriodStartAt = (int) ($fresh['period_start_at'] ?? 0);
|
||||
if ($freshPeriodStartAt <= 0) {
|
||||
return;
|
||||
}
|
||||
$freshTimeoutAt = $freshPeriodStartAt + $periodSeconds + self::PAYOUT_GRACE_SECONDS + self::STARTUP_RECOVER_GRACE_SECONDS;
|
||||
if (time() <= $freshTimeoutAt) {
|
||||
$freshResultNumber = isset($fresh['result_number']) ? (int) $fresh['result_number'] : 0;
|
||||
if ($freshResultNumber > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -92,13 +167,12 @@ final class GameLiveService
|
||||
Db::startTrans();
|
||||
try {
|
||||
$refund = self::refundPendingBetsSummaryForPeriodLocked($recordId, $now);
|
||||
$oldStatus = $freshStatus;
|
||||
$refundedUserCount = count($refund['user_ids']);
|
||||
$refundedOrderCount = (int) ($refund['order_count'] ?? 0);
|
||||
$refundedTotalAmount = is_string($refund['total_amount'] ?? null) ? $refund['total_amount'] : '0.00';
|
||||
$reason = sprintf(
|
||||
'system_recover:from=%d|users=%d|orders=%d|amount=%s',
|
||||
$oldStatus,
|
||||
$freshStatus,
|
||||
$refundedUserCount,
|
||||
$refundedOrderCount,
|
||||
$refundedTotalAmount
|
||||
@@ -114,8 +188,9 @@ final class GameLiveService
|
||||
Db::commit();
|
||||
} catch (Throwable $e) {
|
||||
Db::rollback();
|
||||
Log::warning('game live startup recover failed', [
|
||||
Log::warning('game live startup abnormal recover failed', [
|
||||
'record_id' => $recordId,
|
||||
'status' => $status,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
return;
|
||||
@@ -129,7 +204,7 @@ final class GameLiveService
|
||||
}
|
||||
GameRecordService::bootstrapPeriodWhenRuntimeEnabled();
|
||||
self::publishSnapshot(null);
|
||||
Log::info('game live startup recovered abnormal period', [
|
||||
Log::info('game live startup marked abnormal and refunded', [
|
||||
'record_id' => $recordId,
|
||||
'old_status' => $freshStatus,
|
||||
'refunded_user_count' => count($refund['user_ids']),
|
||||
@@ -141,6 +216,34 @@ final class GameLiveService
|
||||
}
|
||||
}
|
||||
|
||||
private static function finalizePayoutForRecordLocked(int $recordId): void
|
||||
{
|
||||
$now = time();
|
||||
Db::startTrans();
|
||||
try {
|
||||
Db::name('game_record')->where('id', $recordId)->where('status', 3)->update([
|
||||
'status' => 4,
|
||||
'payout_until' => null,
|
||||
'update_time' => $now,
|
||||
]);
|
||||
GameRecordService::createNextRecordAfterDraw();
|
||||
Db::commit();
|
||||
} catch (Throwable $e) {
|
||||
Db::rollback();
|
||||
Log::warning('game live startup finalize payout failed', [
|
||||
'record_id' => $recordId,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
return;
|
||||
}
|
||||
GameHotDataCoordinator::afterGameRecordCommitted($recordId);
|
||||
try {
|
||||
GameRecordStatService::refreshForRecordId($recordId);
|
||||
} catch (Throwable) {
|
||||
}
|
||||
self::publishSnapshot(null);
|
||||
}
|
||||
|
||||
public static function buildSnapshot(?int $recordId = null): array
|
||||
{
|
||||
$record = self::resolveRecord($recordId);
|
||||
@@ -170,9 +273,12 @@ final class GameLiveService
|
||||
}
|
||||
|
||||
$bets = Db::name('bet_order')
|
||||
->where('period_id', $rid)
|
||||
->order('id', 'desc')
|
||||
->alias('bo')
|
||||
->leftJoin('user gu', 'gu.id = bo.user_id')
|
||||
->where('bo.period_id', $rid)
|
||||
->order('bo.id', 'desc')
|
||||
->limit(200)
|
||||
->field('bo.id,bo.user_id,bo.period_no,bo.pick_numbers,bo.total_amount,bo.streak_at_bet,bo.create_time,gu.username as user_username')
|
||||
->select()
|
||||
->toArray();
|
||||
|
||||
@@ -218,6 +324,7 @@ final class GameLiveService
|
||||
return [
|
||||
'id' => (int) $row['id'],
|
||||
'user_id' => (int) $row['user_id'],
|
||||
'username' => isset($row['user_username']) && is_string($row['user_username']) ? $row['user_username'] : '',
|
||||
'period_no' => (string) $row['period_no'],
|
||||
'pick_numbers' => $row['pick_numbers'],
|
||||
'total_amount' => (string) $row['total_amount'],
|
||||
|
||||
Reference in New Issue
Block a user