From 6b318892610cdac2aa36dfff7f83a8657bf5185b Mon Sep 17 00:00:00 2001 From: wong <106998207@qq.com> Date: Mon, 19 Jan 2026 10:30:09 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../command/TaskSchedulerCommand.php | 174 ++++++++++++++++-- .../job/MessageChatroomListJob.php | 16 +- 2 files changed, 176 insertions(+), 14 deletions(-) diff --git a/Server/application/command/TaskSchedulerCommand.php b/Server/application/command/TaskSchedulerCommand.php index 943bfbfc..3586622f 100644 --- a/Server/application/command/TaskSchedulerCommand.php +++ b/Server/application/command/TaskSchedulerCommand.php @@ -432,6 +432,10 @@ class TaskSchedulerCommand extends Command $logMessage .= "执行时间: " . date('Y-m-d H:i:s') . "\n"; $logMessage .= "执行目录: {$executionPath}\n"; $logMessage .= "命令: {$command}\n"; + $logMessage .= "[DEBUG] 任务配置: " . json_encode($task, JSON_UNESCAPED_UNICODE) . "\n"; + $logMessage .= "[DEBUG] 当前工作目录: " . getcwd() . "\n"; + $logMessage .= "[DEBUG] PHP版本: " . PHP_VERSION . "\n"; + $logMessage .= "[DEBUG] 操作系统: " . PHP_OS . "\n"; $logMessage .= str_repeat('=', 60) . "\n"; file_put_contents($logFile, $logMessage, FILE_APPEND); @@ -445,16 +449,30 @@ class TaskSchedulerCommand extends Command 2 => ['pipe', 'w'], // stderr ]; + // [DEBUG] 记录进程启动前信息 + $debugLog = "[DEBUG] 准备启动进程\n"; + $debugLog .= "[DEBUG] PHP路径: {$phpPath}\n"; + $debugLog .= "[DEBUG] Think路径: {$thinkPath}\n"; + $debugLog .= "[DEBUG] 执行目录: {$executionPath}\n"; + $debugLog .= "[DEBUG] 完整命令: {$command}\n"; + $debugLog .= "[DEBUG] 超时设置: {$timeout}秒\n"; + file_put_contents($logFile, $debugLog, FILE_APPEND); + $process = @proc_open($command, $descriptorspec, $pipes, $executionPath); if (!is_resource($process)) { $errorMsg = "任务执行失败: 无法启动进程"; + $errorMsg .= "\n[DEBUG] proc_open 返回: " . var_export($process, true); + $errorMsg .= "\n[DEBUG] 错误信息: " . error_get_last()['message'] ?? '无错误信息'; Log::error($errorMsg, ['task' => $taskId]); file_put_contents($logFile, $errorMsg . "\n", FILE_APPEND); $this->removeLock($taskId); // 删除锁文件 return; } + // [DEBUG] 记录进程启动成功 + file_put_contents($logFile, "[DEBUG] 进程启动成功,进程资源类型: " . get_resource_type($process) . "\n", FILE_APPEND); + // 设置非阻塞模式 stream_set_blocking($pipes[1], false); stream_set_blocking($pipes[2], false); @@ -462,34 +480,80 @@ class TaskSchedulerCommand extends Command $startWaitTime = time(); $output = ''; $error = ''; + $loopCount = 0; + $lastStatusCheck = 0; // 等待进程完成或超时 while (true) { + $loopCount++; $status = proc_get_status($process); + // [DEBUG] 每10次循环记录一次状态(减少日志量) + if ($loopCount % 10 == 0 || time() - $lastStatusCheck > 5) { + $elapsed = time() - $startWaitTime; + $debugStatus = "[DEBUG] 循环 #{$loopCount}, 已运行 {$elapsed}秒\n"; + $debugStatus .= "[DEBUG] 进程状态: running=" . ($status['running'] ? 'true' : 'false'); + if (isset($status['exitcode'])) { + $debugStatus .= ", exitcode=" . $status['exitcode']; + } + if (isset($status['signaled'])) { + $debugStatus .= ", signaled=" . ($status['signaled'] ? 'true' : 'false'); + } + if (isset($status['termsig'])) { + $debugStatus .= ", termsig=" . $status['termsig']; + } + $debugStatus .= "\n"; + file_put_contents($logFile, $debugStatus, FILE_APPEND); + $lastStatusCheck = time(); + } + // 读取输出 - $output .= stream_get_contents($pipes[1]); - $error .= stream_get_contents($pipes[2]); + $outputChunk = stream_get_contents($pipes[1]); + $errorChunk = stream_get_contents($pipes[2]); + + if (!empty($outputChunk)) { + $output .= $outputChunk; + file_put_contents($logFile, "[DEBUG] 标准输出片段: " . substr($outputChunk, 0, 200) . "\n", FILE_APPEND); + } + + if (!empty($errorChunk)) { + $error .= $errorChunk; + file_put_contents($logFile, "[DEBUG] 错误输出片段: " . substr($errorChunk, 0, 200) . "\n", FILE_APPEND); + } // 检查是否完成 if (!$status['running']) { + // [DEBUG] 记录进程结束时的详细状态 + $debugEnd = "[DEBUG] 进程已结束\n"; + $debugEnd .= "[DEBUG] 最终状态: " . json_encode($status, JSON_UNESCAPED_UNICODE) . "\n"; + if (isset($status['exitcode'])) { + $debugEnd .= "[DEBUG] proc_get_status 返回的退出码: " . $status['exitcode'] . "\n"; + } + file_put_contents($logFile, $debugEnd, FILE_APPEND); break; } // 检查超时 if ((time() - $startWaitTime) > $timeout) { + $timeoutMsg = "任务执行超时({$timeout}秒),终止进程\n"; + $timeoutMsg .= "[DEBUG] 当前循环次数: {$loopCount}\n"; + $timeoutMsg .= "[DEBUG] 已运行时间: " . (time() - $startWaitTime) . "秒\n"; Log::warning("任务执行超时({$timeout}秒),终止进程", ['task' => $taskId]); - file_put_contents($logFile, "任务执行超时({$timeout}秒),终止进程\n", FILE_APPEND); + file_put_contents($logFile, $timeoutMsg, FILE_APPEND); if (function_exists('proc_terminate')) { - proc_terminate($process); + $terminateResult = proc_terminate($process); + file_put_contents($logFile, "[DEBUG] proc_terminate 返回: " . var_export($terminateResult, true) . "\n", FILE_APPEND); + } else { + file_put_contents($logFile, "[DEBUG] proc_terminate 函数不可用\n", FILE_APPEND); } // 关闭管道 @fclose($pipes[0]); @fclose($pipes[1]); @fclose($pipes[2]); - proc_close($process); + $closeResult = proc_close($process); + file_put_contents($logFile, "[DEBUG] 超时后 proc_close 返回: {$closeResult}\n", FILE_APPEND); $this->removeLock($taskId); // 删除锁文件 return; @@ -500,17 +564,43 @@ class TaskSchedulerCommand extends Command } // 读取剩余输出 - $output .= stream_get_contents($pipes[1]); - $error .= stream_get_contents($pipes[2]); + $remainingOutput = stream_get_contents($pipes[1]); + $remainingError = stream_get_contents($pipes[2]); + + if (!empty($remainingOutput)) { + $output .= $remainingOutput; + file_put_contents($logFile, "[DEBUG] 剩余标准输出: " . substr($remainingOutput, 0, 500) . "\n", FILE_APPEND); + } + + if (!empty($remainingError)) { + $error .= $remainingError; + file_put_contents($logFile, "[DEBUG] 剩余错误输出: " . substr($remainingError, 0, 500) . "\n", FILE_APPEND); + } + + // [DEBUG] 记录关闭管道前的状态 + file_put_contents($logFile, "[DEBUG] 准备关闭管道,输出长度: " . strlen($output) . ", 错误长度: " . strlen($error) . "\n", FILE_APPEND); // 关闭管道 - @fclose($pipes[0]); - @fclose($pipes[1]); - @fclose($pipes[2]); + $closeResults = []; + $closeResults['stdin'] = @fclose($pipes[0]); + $closeResults['stdout'] = @fclose($pipes[1]); + $closeResults['stderr'] = @fclose($pipes[2]); + file_put_contents($logFile, "[DEBUG] 管道关闭结果: " . json_encode($closeResults, JSON_UNESCAPED_UNICODE) . "\n", FILE_APPEND); // 获取退出码 $exitCode = proc_close($process); + // [DEBUG] 记录退出码获取结果 + file_put_contents($logFile, "[DEBUG] proc_close 返回的退出码: {$exitCode}\n", FILE_APPEND); + file_put_contents($logFile, "[DEBUG] 退出码类型: " . gettype($exitCode) . "\n", FILE_APPEND); + if ($exitCode === -1) { + file_put_contents($logFile, "[DEBUG] ⚠️ 退出码为 -1,可能原因:\n", FILE_APPEND); + file_put_contents($logFile, "[DEBUG] 1. 进程被信号终止\n", FILE_APPEND); + file_put_contents($logFile, "[DEBUG] 2. 进程异常终止\n", FILE_APPEND); + file_put_contents($logFile, "[DEBUG] 3. 无法获取进程退出状态\n", FILE_APPEND); + file_put_contents($logFile, "[DEBUG] 4. Windows系统上的特殊返回值\n", FILE_APPEND); + } + // 记录输出 if (!empty($output)) { file_put_contents($logFile, "任务输出:\n{$output}\n", FILE_APPEND); @@ -527,12 +617,29 @@ class TaskSchedulerCommand extends Command // 获取任务名称 $taskName = $task['name'] ?? $taskId; + // 解释退出码含义 + $exitCodeMeaning = $this->getExitCodeMeaning($exitCode); + // 记录任务完成 $logMessage = "\n" . str_repeat('=', 60) . "\n"; $logMessage .= "任务执行完成: {$taskName} ({$taskId})\n"; $logMessage .= "完成时间: " . date('Y-m-d H:i:s') . "\n"; $logMessage .= "执行时长: {$duration} 秒\n"; - $logMessage .= "退出码: {$exitCode}\n"; + $logMessage .= "退出码: {$exitCode} ({$exitCodeMeaning})\n"; + $logMessage .= "[DEBUG] 输出总长度: " . strlen($output) . " 字节\n"; + $logMessage .= "[DEBUG] 错误总长度: " . strlen($error) . " 字节\n"; + if ($exitCode === -1) { + $logMessage .= "[DEBUG] ⚠️ 退出码 -1 详细分析:\n"; + $logMessage .= "[DEBUG] - 是否有错误输出: " . (!empty($error) ? '是' : '否') . "\n"; + $logMessage .= "[DEBUG] - 是否有标准输出: " . (!empty($output) ? '是' : '否') . "\n"; + $logMessage .= "[DEBUG] - 执行时长: {$duration} 秒\n"; + if ($duration < 1) { + $logMessage .= "[DEBUG] - ⚠️ 执行时长过短,可能是进程启动失败\n"; + } + if ($duration > $timeout * 0.9) { + $logMessage .= "[DEBUG] - ⚠️ 执行时长接近超时时间\n"; + } + } $logMessage .= str_repeat('=', 60) . "\n"; file_put_contents($logFile, $logMessage, FILE_APPEND); @@ -548,6 +655,7 @@ class TaskSchedulerCommand extends Command 'name' => $taskName, 'duration' => $duration, 'exit_code' => $exitCode, + 'exit_code_meaning' => $exitCodeMeaning, ]); } @@ -582,6 +690,50 @@ class TaskSchedulerCommand extends Command } } + /** + * 获取退出码的含义说明 + * @param int $exitCode 退出码 + * @return string 退出码含义 + */ + protected function getExitCodeMeaning($exitCode) + { + switch ($exitCode) { + case 0: + return '成功'; + case -1: + return '进程被信号终止或异常终止(可能是被强制终止、超时终止或发生致命错误)'; + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + return '一般性错误'; + case 126: + return '命令不可执行'; + case 127: + return '命令未找到'; + case 128: + return '无效的退出参数'; + case 130: + return '进程被 Ctrl+C 终止 (SIGINT)'; + case 137: + return '进程被 SIGKILL 信号强制终止'; + case 143: + return '进程被 SIGTERM 信号终止'; + default: + if ($exitCode > 128 && $exitCode < 256) { + $signal = $exitCode - 128; + return "进程被信号 {$signal} 终止"; + } + return '未知错误'; + } + } + /** * 清理僵尸进程 */ diff --git a/Server/application/job/MessageChatroomListJob.php b/Server/application/job/MessageChatroomListJob.php index d4d590ea..9f23e48a 100644 --- a/Server/application/job/MessageChatroomListJob.php +++ b/Server/application/job/MessageChatroomListJob.php @@ -80,14 +80,24 @@ class MessageChatroomListJob // 调用添加好友任务获取方法 $result = $messageController->getChatroomList($pageIndex,$pageSize,true); $response = json_decode($result,true); + + // 确保 response 是数组格式 + if (!is_array($response)) { + $response = []; + } // 判断是否成功 - if ($response['code'] == 200) { - $data = $response['data']; + if (isset($response['code']) && $response['code'] == 200) { + $data = isset($response['data']) ? $response['data'] : []; + + // 确保 data 是数组格式 + if (!is_array($data)) { + $data = []; + } // 判断是否有下一页,且未超过最大同步页数 - if (!empty($data) && count($data) > 0) { + if (!empty($data) && is_array($data) && count($data) > 0) { $nextPageIndex = $pageIndex + 1; // 检查是否超过最大同步页数 if ($nextPageIndex < self::MAX_SYNC_PAGES) {