1.修复关闭自动创建下一局后还自动创建下一期
This commit is contained in:
@@ -244,7 +244,7 @@ final class GameLiveService
|
||||
'payout_until' => null,
|
||||
'update_time' => $now,
|
||||
]);
|
||||
GameRecordService::createNextRecordAfterDraw();
|
||||
$newPeriodNo = GameRecordService::createNextRecordAfterDraw();
|
||||
Db::commit();
|
||||
} catch (Throwable $e) {
|
||||
Db::rollback();
|
||||
@@ -259,6 +259,11 @@ final class GameLiveService
|
||||
GameRecordStatService::refreshForRecordId($recordId);
|
||||
} catch (Throwable) {
|
||||
}
|
||||
if (!GameRecordService::isLiveRuntimeEnabled()) {
|
||||
self::voidRemainingOpenRoundsOnMaintenanceAfterFinalize();
|
||||
} elseif (is_string($newPeriodNo ?? null) && $newPeriodNo !== '') {
|
||||
self::publishImmediateBettingTickAfterFinalize();
|
||||
}
|
||||
self::publishSnapshot(null);
|
||||
}
|
||||
|
||||
@@ -689,6 +694,7 @@ final class GameLiveService
|
||||
if ($resultNumber === false || $resultNumber < 1) {
|
||||
$resultNumber = null;
|
||||
}
|
||||
$newPeriodNo = null;
|
||||
Db::startTrans();
|
||||
try {
|
||||
Db::name('game_record')->where('id', $id)->update([
|
||||
@@ -696,9 +702,7 @@ final class GameLiveService
|
||||
'payout_until' => null,
|
||||
'update_time' => time(),
|
||||
]);
|
||||
if (GameRecordService::isLiveRuntimeEnabled()) {
|
||||
GameRecordService::createNextRecordRowIfNoActive();
|
||||
}
|
||||
$newPeriodNo = GameRecordService::createNextRecordAfterDraw();
|
||||
Db::commit();
|
||||
} catch (Throwable $e) {
|
||||
Db::rollback();
|
||||
@@ -710,7 +714,11 @@ final class GameLiveService
|
||||
GameRecordStatService::refreshForRecordId($id);
|
||||
self::publishPublicPeriodFinished($id, $periodNo, $resultNumber);
|
||||
self::publishSnapshot(null);
|
||||
self::publishImmediateBettingTickAfterFinalize();
|
||||
if (!GameRecordService::isLiveRuntimeEnabled()) {
|
||||
self::voidRemainingOpenRoundsOnMaintenanceAfterFinalize();
|
||||
} elseif (is_string($newPeriodNo ?? null) && $newPeriodNo !== '') {
|
||||
self::publishImmediateBettingTickAfterFinalize();
|
||||
}
|
||||
} finally {
|
||||
GameHotDataLock::release(GameHotDataLock::TYPE_GAME_RECORD, (string) $id, $lock['token'], $lock['redis_lock']);
|
||||
}
|
||||
@@ -737,6 +745,126 @@ final class GameLiveService
|
||||
self::drawResult((int) $record['id'], null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭「自动创建下一局」时:作废除当前 draining 局外的其它下注/封盘期(历史重复开局遗留),避免被 tickAutoDraw 当成新一局继续跑。
|
||||
*/
|
||||
public static function voidOrphanActiveRoundsOnRuntimeDisabled(): void
|
||||
{
|
||||
if (GameRecordService::isLiveRuntimeEnabled()) {
|
||||
return;
|
||||
}
|
||||
$canonical = GameHotDataRedis::gameRecordActive();
|
||||
if (!$canonical) {
|
||||
return;
|
||||
}
|
||||
$keepId = filter_var($canonical['id'] ?? 0, FILTER_VALIDATE_INT);
|
||||
if ($keepId === false || $keepId <= 0) {
|
||||
return;
|
||||
}
|
||||
$reason = (string) __('Orphan period closed: auto-create next round is disabled');
|
||||
$rows = Db::name('game_record')
|
||||
->whereIn('status', [0, 1])
|
||||
->where('id', '<>', $keepId)
|
||||
->order('id', 'asc')
|
||||
->select()
|
||||
->toArray();
|
||||
foreach ($rows as $row) {
|
||||
$rid = filter_var($row['id'] ?? 0, FILTER_VALIDATE_INT);
|
||||
if ($rid === false || $rid <= 0) {
|
||||
continue;
|
||||
}
|
||||
self::voidOpenPeriodInternal($rid, $reason);
|
||||
}
|
||||
GameHotDataRedis::gameRecordRefreshAggregateCaches();
|
||||
self::publishSnapshot(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 维护模式:本期派彩结单后,清理仍停留在下注/封盘的遗留对局(不插入新期)。
|
||||
*/
|
||||
public static function voidRemainingOpenRoundsOnMaintenanceAfterFinalize(): void
|
||||
{
|
||||
if (GameRecordService::isLiveRuntimeEnabled()) {
|
||||
return;
|
||||
}
|
||||
$reason = (string) __('Open period closed after payout: game is in maintenance');
|
||||
$rows = Db::name('game_record')
|
||||
->whereIn('status', [0, 1])
|
||||
->order('id', 'asc')
|
||||
->select()
|
||||
->toArray();
|
||||
foreach ($rows as $row) {
|
||||
$rid = filter_var($row['id'] ?? 0, FILTER_VALIDATE_INT);
|
||||
if ($rid === false || $rid <= 0) {
|
||||
continue;
|
||||
}
|
||||
self::voidOpenPeriodInternal($rid, $reason);
|
||||
}
|
||||
GameHotDataRedis::gameRecordRefreshAggregateCaches();
|
||||
}
|
||||
|
||||
/**
|
||||
* 作废单期(仅 status 0/1),不修改自动开局开关。
|
||||
*
|
||||
* @return array{ok: bool, msg?: string}
|
||||
*/
|
||||
private static function voidOpenPeriodInternal(int $recordId, string $voidReason): array
|
||||
{
|
||||
if ($recordId <= 0) {
|
||||
return ['ok' => false, 'msg' => __('Parameter error')];
|
||||
}
|
||||
$reason = trim($voidReason);
|
||||
if ($reason === '') {
|
||||
return ['ok' => false, 'msg' => __('Void reason is required')];
|
||||
}
|
||||
$record = Db::name('game_record')->where('id', $recordId)->find();
|
||||
if (!$record) {
|
||||
return ['ok' => false, 'msg' => __('No active game in progress')];
|
||||
}
|
||||
$st = (int) ($record['status'] ?? -1);
|
||||
if (!in_array($st, [0, 1], true)) {
|
||||
return ['ok' => false, 'msg' => __('Current period cannot be voided')];
|
||||
}
|
||||
$lock = GameHotDataLock::tryAcquireWithWait(GameHotDataLock::TYPE_GAME_RECORD, (string) $recordId, 3000);
|
||||
if (!$lock['acquired']) {
|
||||
return ['ok' => false, 'msg' => __('Another operation is in progress for this period; please try again later')];
|
||||
}
|
||||
$refundedUserIds = [];
|
||||
try {
|
||||
$now = time();
|
||||
Db::startTrans();
|
||||
try {
|
||||
$refund = self::refundPendingBetsSummaryForPeriodLocked($recordId, $now);
|
||||
$refundedUserIds = $refund['user_ids'];
|
||||
Db::name('game_record')->where('id', $recordId)->update([
|
||||
'status' => 5,
|
||||
'void_reason' => $reason,
|
||||
'pending_draw_number' => null,
|
||||
'payout_until' => null,
|
||||
'ai_locked_number' => null,
|
||||
'update_time' => $now,
|
||||
]);
|
||||
Db::commit();
|
||||
} catch (Throwable $e) {
|
||||
Db::rollback();
|
||||
return ['ok' => false, 'msg' => __('Void failed') . ': ' . $e->getMessage()];
|
||||
}
|
||||
GameHotDataCoordinator::afterGameRecordCommitted($recordId);
|
||||
foreach ($refundedUserIds as $uid) {
|
||||
if ($uid > 0) {
|
||||
GameHotDataCoordinator::afterUserCommitted($uid);
|
||||
}
|
||||
}
|
||||
return [
|
||||
'ok' => true,
|
||||
'msg' => __('Period voided'),
|
||||
'refund' => $refund,
|
||||
];
|
||||
} finally {
|
||||
GameHotDataLock::release(GameHotDataLock::TYPE_GAME_RECORD, (string) $recordId, $lock['token'], $lock['redis_lock']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 作废当前期(仅 status 为下注/封盘):待开奖注单退款,本期置为已作废,并关闭运行开关。
|
||||
*
|
||||
@@ -768,50 +896,22 @@ final class GameLiveService
|
||||
return ['ok' => false, 'msg' => __('Current period cannot be voided')];
|
||||
}
|
||||
$rid = (int) $record['id'];
|
||||
$lock = GameHotDataLock::tryAcquireWithWait(GameHotDataLock::TYPE_GAME_RECORD, (string) $rid, 3000);
|
||||
if (!$lock['acquired']) {
|
||||
return ['ok' => false, 'msg' => __('Another operation is in progress for this period; please try again later')];
|
||||
$internal = self::voidOpenPeriodInternal($rid, $reason);
|
||||
if (!($internal['ok'] ?? false)) {
|
||||
$errMsg = $internal['msg'] ?? null;
|
||||
return ['ok' => false, 'msg' => is_string($errMsg) ? $errMsg : __('Void failed')];
|
||||
}
|
||||
$refundedUserIds = [];
|
||||
try {
|
||||
$now = time();
|
||||
$refund = ['user_ids' => [], 'order_count' => 0, 'total_amount' => '0.00', 'order_ids' => []];
|
||||
Db::startTrans();
|
||||
try {
|
||||
$refund = self::refundPendingBetsSummaryForPeriodLocked($rid, $now);
|
||||
$refundedUserIds = $refund['user_ids'];
|
||||
Db::name('game_record')->where('id', $rid)->update([
|
||||
'status' => 5,
|
||||
'void_reason' => $reason,
|
||||
'pending_draw_number' => null,
|
||||
'payout_until' => null,
|
||||
'ai_locked_number' => null,
|
||||
'update_time' => $now,
|
||||
]);
|
||||
Db::commit();
|
||||
} catch (Throwable $e) {
|
||||
Db::rollback();
|
||||
return ['ok' => false, 'msg' => __('Void failed') . ': ' . $e->getMessage()];
|
||||
}
|
||||
GameRecordService::setAutoCreateEnabled(false);
|
||||
GameHotDataCoordinator::afterGameRecordCommitted($rid);
|
||||
GameHotDataCoordinator::afterGameConfigKeyCommitted(GameRecordService::KEY_AUTO_CREATE);
|
||||
foreach ($refundedUserIds as $uid) {
|
||||
if ($uid > 0) {
|
||||
GameHotDataCoordinator::afterUserCommitted($uid);
|
||||
}
|
||||
}
|
||||
self::publishSnapshot(null);
|
||||
GameRecordService::setAutoCreateEnabled(false);
|
||||
GameHotDataCoordinator::afterGameConfigKeyCommitted(GameRecordService::KEY_AUTO_CREATE);
|
||||
self::publishSnapshot(null);
|
||||
$refund = $internal['refund'] ?? null;
|
||||
|
||||
return [
|
||||
'ok' => true,
|
||||
'msg' => __('Period voided'),
|
||||
'record' => self::reloadRecord($rid),
|
||||
'refund' => $refund,
|
||||
];
|
||||
} finally {
|
||||
GameHotDataLock::release(GameHotDataLock::TYPE_GAME_RECORD, (string) $rid, $lock['token'], $lock['redis_lock']);
|
||||
}
|
||||
return [
|
||||
'ok' => true,
|
||||
'msg' => __('Period voided'),
|
||||
'record' => self::reloadRecord($rid),
|
||||
'refund' => is_array($refund) ? $refund : null,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user