修复随机号码前先按权重随机工单,并修复降权号码筛选与清理
This commit is contained in:
@@ -21,11 +21,14 @@ class SplitTicketSyncService
|
||||
|
||||
private SplitTicketSyncLockService $lockService;
|
||||
|
||||
private SplitTicketSyncDispatchService $dispatchService;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->numberSync = new SplitTicketNumberSyncService();
|
||||
$this->ruleService = new SplitTicketRuleService();
|
||||
$this->lockService = new SplitTicketSyncLockService();
|
||||
$this->dispatchService = new SplitTicketSyncDispatchService();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -126,7 +129,7 @@ class SplitTicketSyncService
|
||||
);
|
||||
|
||||
$successCount = count(array_filter($processed, static function (array $row): bool {
|
||||
return !empty($row['success']);
|
||||
return !empty($row['dispatched']);
|
||||
}));
|
||||
$failedCount = count($processed) - $successCount;
|
||||
|
||||
@@ -151,7 +154,7 @@ class SplitTicketSyncService
|
||||
}
|
||||
|
||||
/**
|
||||
* 直连 PHP 通道:按周期同步,不占 Node 名额
|
||||
* 直连 PHP 通道:挑选到期工单并投递后台 CLI,不占 Node 名额
|
||||
*
|
||||
* @param list<string> $directTypes
|
||||
* @return array{
|
||||
@@ -171,16 +174,10 @@ class SplitTicketSyncService
|
||||
$list = $this->loadOpenTicketsForTypes($directTypes, $failThreshold, 0);
|
||||
$candidateIds = $this->extractTicketIds($list);
|
||||
|
||||
SplitTicketSyncLogger::logCron('direct channel start', [
|
||||
'types' => $directTypes,
|
||||
'candidateCount' => count($list),
|
||||
]);
|
||||
|
||||
/** @var list<array<string, mixed>> $processed */
|
||||
$processed = [];
|
||||
/** @var list<array<string, mixed>> $skipped */
|
||||
/** @var list<array<string,mixed>> $dueList */
|
||||
$dueList = [];
|
||||
/** @var list<array<string,mixed>> $skipped */
|
||||
$skipped = [];
|
||||
$count = 0;
|
||||
|
||||
foreach ($list as $ticket) {
|
||||
$ticketId = (int) $ticket['id'];
|
||||
@@ -193,42 +190,60 @@ class SplitTicketSyncService
|
||||
$this->logCronCandidateSkipped($ticketId, $ticketType, $ticketUrl, $skip, 'direct');
|
||||
continue;
|
||||
}
|
||||
$dueList[] = $ticket;
|
||||
}
|
||||
|
||||
$result = $this->syncOne($ticketId, false, true, 'auto');
|
||||
if (!empty($result['skipped'])) {
|
||||
$skipReason = (string) ($result['message'] ?? '已跳过');
|
||||
$skipped[] = $this->buildCronTicketEntry($ticketId, $ticketType, $ticketUrl, $skipReason);
|
||||
$this->logCronCandidateSkipped($ticketId, $ticketType, $ticketUrl, $skipReason, 'direct');
|
||||
continue;
|
||||
}
|
||||
SplitTicketSyncLogger::logCron('direct channel start', [
|
||||
'types' => $directTypes,
|
||||
'candidateCount' => count($list),
|
||||
'dueCount' => count($dueList),
|
||||
]);
|
||||
|
||||
$dispatchResult = $this->dispatchService->dispatchAuto($dueList);
|
||||
$skipped = array_merge($skipped, $this->mapDispatchSkippedToCron($dispatchResult['skipped']));
|
||||
$failed = $this->mapDispatchFailedToCron($dispatchResult['failed']);
|
||||
|
||||
foreach ($failed as $row) {
|
||||
$skipped[] = $row;
|
||||
$this->logCronCandidateSkipped(
|
||||
(int) $row['ticketId'],
|
||||
(string) $row['ticketType'],
|
||||
(string) $row['ticketUrl'],
|
||||
(string) $row['reason'],
|
||||
'direct'
|
||||
);
|
||||
}
|
||||
|
||||
/** @var list<array<string,mixed>> $processed */
|
||||
$processed = [];
|
||||
foreach ($dispatchResult['queued'] as $row) {
|
||||
$processed[] = [
|
||||
'ticketId' => $ticketId,
|
||||
'ticketType' => $ticketType,
|
||||
'ticketUrl' => $ticketUrl,
|
||||
'ticketId' => (int) ($row['ticketId'] ?? 0),
|
||||
'ticketType' => (string) ($row['ticketType'] ?? ''),
|
||||
'ticketUrl' => (string) ($row['ticketUrl'] ?? ''),
|
||||
'channel' => 'direct',
|
||||
'success' => !empty($result['success']),
|
||||
'message' => (string) ($result['message'] ?? ''),
|
||||
'dispatched' => true,
|
||||
'message' => '已投递后台同步',
|
||||
];
|
||||
$count++;
|
||||
}
|
||||
|
||||
return [
|
||||
'processedCount' => $count,
|
||||
'processedCount' => count($processed),
|
||||
'processed' => $processed,
|
||||
'skipped' => $skipped,
|
||||
'candidateIds' => $candidateIds,
|
||||
'summary' => [
|
||||
'channel' => 'direct',
|
||||
'processedCount' => $count,
|
||||
'processedCount' => count($processed),
|
||||
'skippedCount' => count($skipped),
|
||||
'dispatchMode' => 'async-cli',
|
||||
],
|
||||
'stoppedByNodeBusy' => false,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Node 通道:限流 + 类型公平轮转
|
||||
* Node 通道:限流 + 类型公平轮转 + 异步 CLI 投递
|
||||
*
|
||||
* @param list<string> $nodeTypes
|
||||
* @return array{
|
||||
@@ -269,123 +284,101 @@ class SplitTicketSyncService
|
||||
'dueCount' => count($duePool),
|
||||
'pickedCount' => count($picked),
|
||||
'nodeQueue' => SplitNodeHealthService::getQueueSnapshot(),
|
||||
'dispatchMode' => 'async-cli',
|
||||
]);
|
||||
|
||||
if (!SplitNodeHealthService::canAcceptWork()) {
|
||||
SplitTicketSyncLogger::logCron('node channel skip', [
|
||||
'reason' => 'node queue busy',
|
||||
'queue' => SplitNodeHealthService::getQueueSnapshot(),
|
||||
]);
|
||||
$skipped = [];
|
||||
foreach ($picked as $ticket) {
|
||||
$skipped[] = $this->buildCronTicketEntry(
|
||||
(int) $ticket['id'],
|
||||
(string) $ticket['ticket_type'],
|
||||
(string) $ticket['ticket_url'],
|
||||
'Node 队列繁忙,本轮未执行'
|
||||
);
|
||||
}
|
||||
foreach ($pool as $ticket) {
|
||||
$ticketId = (int) $ticket['id'];
|
||||
if (isset($pickedIdMap[$ticketId])) {
|
||||
continue;
|
||||
}
|
||||
$skip = $this->shouldSkip($ticket);
|
||||
if ($skip !== null) {
|
||||
continue;
|
||||
}
|
||||
$skipped[] = $this->buildCronTicketEntry(
|
||||
$ticketId,
|
||||
(string) $ticket['ticket_type'],
|
||||
(string) $ticket['ticket_url'],
|
||||
sprintf('未进入本轮 Node 候选(前%d条到期工单公平轮转)', $candidateLimit)
|
||||
);
|
||||
}
|
||||
|
||||
return [
|
||||
'processedCount' => 0,
|
||||
'processed' => [],
|
||||
'skipped' => $skipped,
|
||||
'candidateIds' => $candidateIds,
|
||||
'summary' => [
|
||||
'channel' => 'node',
|
||||
'processedCount' => 0,
|
||||
'skippedCount' => count($skipped),
|
||||
'reason' => 'node queue busy',
|
||||
],
|
||||
'stoppedByNodeBusy' => true,
|
||||
];
|
||||
}
|
||||
|
||||
/** @var list<array<string, mixed>> $processed */
|
||||
$processed = [];
|
||||
/** @var list<array<string, mixed>> $skipped */
|
||||
/** @var list<array<string,mixed>> $skipped */
|
||||
$skipped = [];
|
||||
$count = 0;
|
||||
$stoppedByNodeBusy = false;
|
||||
|
||||
foreach ($pool as $ticket) {
|
||||
$ticketId = (int) $ticket['id'];
|
||||
$ticketType = (string) $ticket['ticket_type'];
|
||||
$ticketUrl = (string) $ticket['ticket_url'];
|
||||
|
||||
if (!isset($pickedIdMap[$ticketId])) {
|
||||
$skip = $this->shouldSkip($ticket);
|
||||
if ($skip !== null) {
|
||||
continue;
|
||||
}
|
||||
$skipped[] = $this->buildCronTicketEntry(
|
||||
$ticketId,
|
||||
$ticketType,
|
||||
$ticketUrl,
|
||||
sprintf('未进入本轮 Node 候选(前%d条到期工单公平轮转)', $candidateLimit)
|
||||
);
|
||||
if (isset($pickedIdMap[$ticketId])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!SplitNodeHealthService::canAcceptWork()) {
|
||||
$stoppedByNodeBusy = true;
|
||||
$skipped[] = $this->buildCronTicketEntry($ticketId, $ticketType, $ticketUrl, 'Node 队列繁忙,停止本轮后续同步');
|
||||
$this->logCronCandidateSkipped($ticketId, $ticketType, $ticketUrl, 'Node 队列繁忙,停止本轮后续同步', 'node');
|
||||
$skip = $this->shouldSkip($ticket);
|
||||
if ($skip !== null) {
|
||||
continue;
|
||||
}
|
||||
$skipped[] = $this->buildCronTicketEntry(
|
||||
$ticketId,
|
||||
(string) $ticket['ticket_type'],
|
||||
(string) $ticket['ticket_url'],
|
||||
sprintf('未进入本轮 Node 候选(前%d条到期工单公平轮转)', $candidateLimit)
|
||||
);
|
||||
}
|
||||
|
||||
$sessionKey = AntiBotConfigBuilder::resolveSessionKey($ticketType, $ticketUrl);
|
||||
$result = $this->syncOne($ticketId, false, true, 'auto');
|
||||
if (!empty($result['skipped'])) {
|
||||
$skipReason = (string) ($result['message'] ?? '已跳过');
|
||||
$skipped[] = $this->buildCronTicketEntry($ticketId, $ticketType, $ticketUrl, $skipReason);
|
||||
$this->logCronCandidateSkipped($ticketId, $ticketType, $ticketUrl, $skipReason, 'node');
|
||||
continue;
|
||||
}
|
||||
$dispatchResult = $this->dispatchService->dispatchAuto($picked);
|
||||
$skipped = array_merge($skipped, $this->mapDispatchSkippedToCron($dispatchResult['skipped']));
|
||||
$failed = $this->mapDispatchFailedToCron($dispatchResult['failed']);
|
||||
|
||||
foreach ($failed as $row) {
|
||||
$skipped[] = $row;
|
||||
$this->logCronCandidateSkipped(
|
||||
(int) $row['ticketId'],
|
||||
(string) $row['ticketType'],
|
||||
(string) $row['ticketUrl'],
|
||||
(string) $row['reason'],
|
||||
'node'
|
||||
);
|
||||
}
|
||||
|
||||
/** @var list<array<string,mixed>> $processed */
|
||||
$processed = [];
|
||||
foreach ($dispatchResult['queued'] as $row) {
|
||||
$processed[] = [
|
||||
'ticketId' => $ticketId,
|
||||
'ticketType' => $ticketType,
|
||||
'ticketUrl' => $ticketUrl,
|
||||
'sessionKey' => $sessionKey,
|
||||
'ticketId' => (int) ($row['ticketId'] ?? 0),
|
||||
'ticketType' => (string) ($row['ticketType'] ?? ''),
|
||||
'ticketUrl' => (string) ($row['ticketUrl'] ?? ''),
|
||||
'sessionKey' => (string) ($row['sessionKey'] ?? ''),
|
||||
'channel' => 'node',
|
||||
'success' => !empty($result['success']),
|
||||
'message' => (string) ($result['message'] ?? ''),
|
||||
'dispatched' => true,
|
||||
'message' => '已投递后台同步',
|
||||
];
|
||||
$count++;
|
||||
}
|
||||
|
||||
return [
|
||||
'processedCount' => $count,
|
||||
'processedCount' => count($processed),
|
||||
'processed' => $processed,
|
||||
'skipped' => $skipped,
|
||||
'candidateIds' => $candidateIds,
|
||||
'summary' => [
|
||||
'channel' => 'node',
|
||||
'processedCount' => $count,
|
||||
'processedCount' => count($processed),
|
||||
'skippedCount' => count($skipped),
|
||||
'maxPerRun' => $maxPerRun,
|
||||
'dispatchMode' => 'async-cli',
|
||||
],
|
||||
'stoppedByNodeBusy' => $stoppedByNodeBusy,
|
||||
'stoppedByNodeBusy' => $dispatchResult['stoppedByNodeBusy'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<array<string,mixed>> $rows
|
||||
* @return list<array{ticketId:int,ticketType:string,ticketUrl:string,reason:string}>
|
||||
*/
|
||||
private function mapDispatchSkippedToCron(array $rows): array
|
||||
{
|
||||
$result = [];
|
||||
foreach ($rows as $row) {
|
||||
$result[] = $this->buildCronTicketEntry(
|
||||
(int) ($row['ticketId'] ?? 0),
|
||||
(string) ($row['ticketType'] ?? ''),
|
||||
(string) ($row['ticketUrl'] ?? ''),
|
||||
(string) ($row['reason'] ?? '已跳过')
|
||||
);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<array<string,mixed>> $rows
|
||||
* @return list<array{ticketId:int,ticketType:string,ticketUrl:string,reason:string}>
|
||||
*/
|
||||
private function mapDispatchFailedToCron(array $rows): array
|
||||
{
|
||||
return $this->mapDispatchSkippedToCron($rows);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<string> $types
|
||||
* @return list<Ticket>
|
||||
|
||||
Reference in New Issue
Block a user