修正 Proxied、 SSL/TLS 设为 Flexible、开启 Always Use HTTPS
This commit is contained in:
@@ -14,8 +14,6 @@ use think\Exception;
|
||||
*/
|
||||
class SplitTicketSyncService
|
||||
{
|
||||
private const FAIL_PAUSE_THRESHOLD = 5;
|
||||
|
||||
private SplitTicketNumberSyncService $numberSync;
|
||||
|
||||
private SplitTicketRuleService $ruleService;
|
||||
@@ -38,24 +36,42 @@ class SplitTicketSyncService
|
||||
{
|
||||
$ticket = Ticket::get($ticketId);
|
||||
if (!$ticket) {
|
||||
SplitTicketSyncLogger::log('sync', 'ticket not found', ['ticketId' => $ticketId]);
|
||||
return ['success' => false, 'message' => '工单不存在'];
|
||||
}
|
||||
|
||||
SplitTicketSyncLogger::setTicketContext($ticketId, (string) $ticket['ticket_type']);
|
||||
SplitTicketSyncLogger::log('sync', 'syncOne start', [
|
||||
'force' => $force,
|
||||
'status' => (string) $ticket['status'],
|
||||
'syncFailCount' => (int) ($ticket['sync_fail_count'] ?? 0),
|
||||
'syncTime' => (int) ($ticket['sync_time'] ?? 0),
|
||||
'pageUrl' => (string) $ticket['ticket_url'],
|
||||
'nodeHost' => SplitSyncConfigService::getNodeHost(),
|
||||
]);
|
||||
|
||||
if (!$force) {
|
||||
$skip = $this->shouldSkip($ticket);
|
||||
if ($skip !== null) {
|
||||
SplitTicketSyncLogger::log('sync', 'skipped', ['reason' => $skip]);
|
||||
SplitTicketSyncLogger::clearTicketContext();
|
||||
return ['success' => false, 'message' => $skip, 'skipped' => true];
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->lockService->acquire($ticketId)) {
|
||||
SplitTicketSyncLogger::log('sync', 'lock busy', ['ticketId' => $ticketId]);
|
||||
SplitTicketSyncLogger::clearTicketContext();
|
||||
return ['success' => false, 'message' => '工单正在同步中', 'skipped' => true];
|
||||
}
|
||||
|
||||
try {
|
||||
return $this->doSync($ticket);
|
||||
$result = $this->doSync($ticket);
|
||||
SplitTicketSyncLogger::log('sync', 'syncOne end', $result);
|
||||
return $result;
|
||||
} finally {
|
||||
$this->lockService->release($ticketId);
|
||||
SplitTicketSyncLogger::clearTicketContext();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,13 +81,25 @@ class SplitTicketSyncService
|
||||
public function syncDueTickets(): int
|
||||
{
|
||||
$count = 0;
|
||||
$list = Ticket::where('status', 'normal')
|
||||
->where('sync_fail_count', '<', self::FAIL_PAUSE_THRESHOLD)
|
||||
->select();
|
||||
$failThreshold = SplitSyncConfigService::getFailPauseThreshold();
|
||||
$query = Ticket::where('status', 'normal');
|
||||
if ($failThreshold > 0) {
|
||||
$query->where('sync_fail_count', '<', $failThreshold);
|
||||
}
|
||||
$list = $query->select();
|
||||
|
||||
SplitTicketSyncLogger::log('cron', 'scan start', [
|
||||
'candidateCount' => count($list),
|
||||
]);
|
||||
|
||||
foreach ($list as $ticket) {
|
||||
$skip = $this->shouldSkip($ticket);
|
||||
if ($skip !== null) {
|
||||
SplitTicketSyncLogger::log('cron', 'candidate skipped', [
|
||||
'ticketId' => (int) $ticket['id'],
|
||||
'ticketType' => (string) $ticket['ticket_type'],
|
||||
'reason' => $skip,
|
||||
]);
|
||||
continue;
|
||||
}
|
||||
$result = $this->syncOne((int) $ticket['id'], false);
|
||||
@@ -81,6 +109,7 @@ class SplitTicketSyncService
|
||||
$count++;
|
||||
}
|
||||
|
||||
SplitTicketSyncLogger::log('cron', 'scan end', ['processedCount' => $count]);
|
||||
return $count;
|
||||
}
|
||||
|
||||
@@ -92,15 +121,21 @@ class SplitTicketSyncService
|
||||
$ticketType = (string) $ticket['ticket_type'];
|
||||
$pageUrl = trim((string) $ticket['ticket_url']);
|
||||
if ($pageUrl === '') {
|
||||
SplitTicketSyncLogger::log('sync', 'empty pageUrl');
|
||||
$this->markFailure($ticket, '工单链接为空');
|
||||
return ['success' => false, 'message' => '工单链接为空'];
|
||||
}
|
||||
|
||||
if (!SplitScrmSpiderFactory::isSupported($ticketType)) {
|
||||
SplitTicketSyncLogger::log('sync', 'spider not supported', ['ticketType' => $ticketType]);
|
||||
$this->markFailure($ticket, '工单类型尚未实现蜘蛛');
|
||||
return ['success' => false, 'message' => '工单类型尚未实现蜘蛛'];
|
||||
}
|
||||
|
||||
SplitTicketSyncLogger::log('sync', 'create spider', [
|
||||
'ticketType' => $ticketType,
|
||||
'hasAccount' => trim((string) ($ticket['account'] ?? '')) !== '',
|
||||
]);
|
||||
$spider = SplitScrmSpiderFactory::create(
|
||||
$ticketType,
|
||||
$pageUrl,
|
||||
@@ -114,22 +149,24 @@ class SplitTicketSyncService
|
||||
|
||||
Db::startTrans();
|
||||
try {
|
||||
SplitTicketSyncLogger::log('sync', 'spider run begin');
|
||||
$finalData = $spider->run();
|
||||
if (!$finalData instanceof UnifiedScrmData) {
|
||||
throw new Exception('蜘蛛返回数据无效');
|
||||
}
|
||||
|
||||
$this->numberSync->syncFromUnifiedData($ticket, $finalData);
|
||||
$this->ruleService->applyNumberRules($ticket);
|
||||
|
||||
$completeCount = max(0, $finalData->todayNewCount);
|
||||
$this->ruleService->applyTicketStatusRules($ticket, $completeCount);
|
||||
|
||||
$freshTicket = Ticket::get((int) $ticket['id']);
|
||||
if ($freshTicket) {
|
||||
$freshTicket = Ticket::get((int) $ticket['id']) ?: $ticket;
|
||||
if ((string) $freshTicket['status'] === 'hidden') {
|
||||
$this->ruleService->cascadeTicketClosedToNumbers($freshTicket);
|
||||
$ticket = $freshTicket;
|
||||
}
|
||||
// 号码开关最后统一由 applyNumberRules 判定(单号上限/下号比率/云控在线)
|
||||
$this->ruleService->applyNumberRules($freshTicket);
|
||||
$ticket = $freshTicket;
|
||||
|
||||
$inboundCount = $this->numberSync->sumInboundForTicket($ticket);
|
||||
$speed = $this->calcSpeedPerHour($ticket, $completeCount);
|
||||
@@ -149,10 +186,17 @@ class SplitTicketSyncService
|
||||
|
||||
$this->applySyncResult($ticket, $payload, true, '');
|
||||
Db::commit();
|
||||
SplitTicketSyncLogger::log('sync', 'db commit ok', $payload);
|
||||
return ['success' => true, 'message' => '同步成功'];
|
||||
} catch (\Throwable $e) {
|
||||
Db::rollback();
|
||||
$msg = mb_substr($e->getMessage(), 0, 255, 'UTF-8');
|
||||
SplitTicketSyncLogger::log('sync', 'exception', [
|
||||
'type' => get_class($e),
|
||||
'message' => $msg,
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine(),
|
||||
]);
|
||||
$this->markFailure($ticket, $msg);
|
||||
return ['success' => false, 'message' => $msg];
|
||||
}
|
||||
@@ -163,8 +207,9 @@ class SplitTicketSyncService
|
||||
if ((string) $ticket['status'] === 'hidden') {
|
||||
return '工单已关闭';
|
||||
}
|
||||
if ((int) ($ticket['sync_fail_count'] ?? 0) >= self::FAIL_PAUSE_THRESHOLD) {
|
||||
return '连续同步失败超过5次已暂停';
|
||||
$failThreshold = SplitSyncConfigService::getFailPauseThreshold();
|
||||
if ($failThreshold > 0 && (int) ($ticket['sync_fail_count'] ?? 0) >= $failThreshold) {
|
||||
return sprintf('连续同步失败超过%d次已暂停', $failThreshold);
|
||||
}
|
||||
if (!SplitScrmSpiderFactory::isSupported((string) $ticket['ticket_type'])) {
|
||||
return '工单类型尚未实现';
|
||||
@@ -174,7 +219,13 @@ class SplitTicketSyncService
|
||||
return '该类型未配置自动同步周期';
|
||||
}
|
||||
$lastSync = (int) ($ticket['sync_time'] ?? 0);
|
||||
if ($lastSync > 0 && (time() - $lastSync) < ($interval * 60)) {
|
||||
$elapsed = $lastSync > 0 ? (time() - $lastSync) : null;
|
||||
if ($lastSync > 0 && $elapsed !== null && $elapsed < ($interval * 60)) {
|
||||
SplitTicketSyncLogger::log('sync', 'interval not reached', [
|
||||
'intervalMinutes' => $interval,
|
||||
'elapsedSeconds' => $elapsed,
|
||||
'needSeconds' => $interval * 60,
|
||||
]);
|
||||
return '未到同步周期';
|
||||
}
|
||||
return null;
|
||||
@@ -208,12 +259,26 @@ class SplitTicketSyncService
|
||||
private function markFailure(Ticket $ticket, string $message): void
|
||||
{
|
||||
$failCount = (int) ($ticket['sync_fail_count'] ?? 0) + 1;
|
||||
$ticket->save([
|
||||
$failThreshold = SplitSyncConfigService::getFailPauseThreshold();
|
||||
$previousSyncStatus = (string) ($ticket['sync_status'] ?? 'pending');
|
||||
$neverSyncedSuccessfully = $previousSyncStatus === 'pending' && (int) ($ticket['sync_time'] ?? 0) <= 0;
|
||||
$update = [
|
||||
'sync_status' => 'error',
|
||||
'sync_time' => time(),
|
||||
'sync_message' => mb_substr($message, 0, 255, 'UTF-8'),
|
||||
'sync_fail_count' => $failCount,
|
||||
]);
|
||||
];
|
||||
// 新建工单首次同步失败:立即关闭;已同步过的工单仍按连续失败阈值关闭
|
||||
if ($neverSyncedSuccessfully || ($failThreshold > 0 && $failCount >= $failThreshold)) {
|
||||
$update['status'] = 'hidden';
|
||||
}
|
||||
$ticket->save($update);
|
||||
if (isset($update['status']) && $update['status'] === 'hidden') {
|
||||
$fresh = Ticket::get((int) $ticket['id']);
|
||||
if ($fresh) {
|
||||
$this->ruleService->cascadeTicketClosedToNumbers($fresh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user