yemeishu 16 цаг өмнө
parent
commit
5ceb84327d

+ 121 - 18
app/Services/ExamPdfExportService.php

@@ -361,16 +361,22 @@ class ExamPdfExportService
         } finally {
             // 【修复】优化临时文件清理逻辑:
             // 1. 合并失败时不删除源文件,便于重试
-            // 2. 合并成功后才删除源文件
-            // 3. 保留合并后的文件一段时间,便于调试
+            // 2. 合并成功后不立即删除源文件,保留2小时用于调试
+            // 3. 保留合并后的文件30分钟用于调试
 
             if ($mergeSuccess && $uploadSuccess) {
-                // 合并成功且上传成功,删除源文件
+                // 【优化】合并成功且上传成功,不立即删除源文件
+                // 改为设置未来删除时间,让源文件保留2小时
                 $sourceFiles = [$examPdfPath, $gradingPdfPath];
                 foreach ($sourceFiles as $file) {
                     if ($file && file_exists($file)) {
-                        @unlink($file);
-                        Log::debug('删除源PDF文件', ['path' => $file]);
+                        // 设置2小时后删除
+                        $deletionTime = time() + 7200; // 2小时 = 7200秒
+                        @touch($file, $deletionTime);
+                        Log::info('源PDF文件将在2小时后自动删除', [
+                            'path' => $file,
+                            'deletion_time' => date('Y-m-d H:i:s', $deletionTime)
+                        ]);
                     }
                 }
 
@@ -1246,6 +1252,12 @@ class ExamPdfExportService
             return null;
         }
 
+        Log::info('ExamPdfExportService: 开始Chrome渲染', [
+            'html_path' => $htmlPath,
+            'tmp_pdf' => $tmpPdf,
+            'chrome_binary' => $chromeBinary
+        ]);
+
         // 设置运行时目录
         $runtimeHome = sys_get_temp_dir() . '/chrome-home';
         $runtimeXdg = sys_get_temp_dir() . '/chrome-xdg';
@@ -1297,40 +1309,84 @@ class ExamPdfExportService
             'XDG_RUNTIME_DIR' => $runtimeXdg,
         ]);
 
-        $process->setTimeout(60);
+        // 【修复】减少超时时间,避免队列任务整体超时
+        // 队列任务默认60秒超时,给Chrome进程设置45秒超时
+        $process->setTimeout(45);
         $killSignal = \defined('SIGKILL') ? \SIGKILL : 9;
 
         try {
             $startedAt = microtime(true);
+            Log::info('ExamPdfExportService: Chrome进程启动', [
+                'start_time' => date('Y-m-d H:i:s', (int)$startedAt),
+                'timeout' => 45
+            ]);
+
             $process->start();
             $pdfGenerated = false;
 
-            // 轮询检测PDF是否生成
+            // 【修复】缩短轮询时间,提高响应速度
             $pollStart = microtime(true);
-            $maxPollSeconds = 30;
+            $maxPollSeconds = 40; // 缩短到40秒(小于Chrome超时45秒)
+            $checkInterval = 100_000; // 100ms检查一次
+
             while ($process->isRunning() && (microtime(true) - $pollStart) < $maxPollSeconds) {
                 if (file_exists($tmpPdf) && filesize($tmpPdf) > 0) {
                     $pdfGenerated = true;
-                    $process->stop(5, $killSignal);
+                    Log::info('ExamPdfExportService: PDF文件已生成,提前终止Chrome', [
+                        'elapsed' => round(microtime(true) - $startedAt, 2) . 's',
+                        'pdf_size' => filesize($tmpPdf)
+                    ]);
+                    $process->stop(2, $killSignal);
                     break;
                 }
-                usleep(200_000);
+                usleep($checkInterval);
             }
 
+            $elapsed = microtime(true) - $startedAt;
+            Log::info('ExamPdfExportService: Chrome轮询结束', [
+                'elapsed' => round($elapsed, 2) . 's',
+                'is_running' => $process->isRunning(),
+                'pdf_exists' => file_exists($tmpPdf),
+                'pdf_size' => file_exists($tmpPdf) ? filesize($tmpPdf) : 0
+            ]);
+
+            // 【优化】强制停止Chrome进程
             if ($process->isRunning()) {
-                $process->stop(5, $killSignal);
+                Log::warning('ExamPdfExportService: Chrome进程仍在运行,强制停止', [
+                    'elapsed' => round($elapsed, 2) . 's'
+                ]);
+                $process->stop(2, $killSignal);
             }
 
             $process->wait();
 
-        } catch (ProcessTimedOutException|ProcessSignaledException $e) {
+        } catch (ProcessTimedOutException $e) {
+            Log::error('ExamPdfExportService: Chrome进程超时', [
+                'timeout' => $e->getExceededTimeout(),
+                'elapsed' => round(microtime(true) - $startedAt, 2) . 's',
+                'html_size' => file_exists($htmlPath) ? filesize($htmlPath) : 0
+            ]);
             if ($process->isRunning()) {
-                $process->stop(5, $killSignal);
+                $process->stop(2, $killSignal);
+            }
+            return $this->handleChromeProcessResult($tmpPdf, $userDataDir, $process, $startedAt);
+        } catch (ProcessSignaledException $e) {
+            Log::warning('ExamPdfExportService: Chrome进程被信号终止', [
+                'signal' => $e->getSignal(),
+                'elapsed' => round(microtime(true) - $startedAt, 2) . 's'
+            ]);
+            if ($process->isRunning()) {
+                $process->stop(2, $killSignal);
             }
             return $this->handleChromeProcessResult($tmpPdf, $userDataDir, $process, $startedAt);
         } catch (\Throwable $e) {
+            Log::error('ExamPdfExportService: Chrome渲染异常', [
+                'error' => $e->getMessage(),
+                'elapsed' => round(microtime(true) - $startedAt, 2) . 's',
+                'trace' => $e->getTraceAsString()
+            ]);
             if ($process->isRunning()) {
-                $process->stop(5, $killSignal);
+                $process->stop(2, $killSignal);
             }
             return $this->handleChromeProcessResult($tmpPdf, $userDataDir, $process, null);
         }
@@ -1343,29 +1399,76 @@ class ExamPdfExportService
      */
     private function handleChromeProcessResult(string $tmpPdf, string $userDataDir, Process $process, ?float $startedAt): ?string
     {
+        $elapsed = $startedAt ? round(microtime(true) - $startedAt, 2) : 0;
         $pdfExists = file_exists($tmpPdf);
         $pdfSize = $pdfExists ? filesize($tmpPdf) : null;
 
         if (!$process->isSuccessful()) {
             if ($pdfExists && $pdfSize > 0) {
                 Log::warning('ExamPdfExportService: Chrome进程异常但生成了PDF', [
+                    'elapsed' => $elapsed . 's',
                     'exit_code' => $process->getExitCode(),
                     'tmp_pdf_size' => $pdfSize,
                 ]);
             } else {
                 Log::error('ExamPdfExportService: Chrome渲染失败', [
+                    'elapsed' => $elapsed . 's',
                     'exit_code' => $process->getExitCode(),
                     'error' => $process->getErrorOutput(),
+                    'tmp_pdf_exists' => $pdfExists,
+                    'tmp_pdf_size' => $pdfSize
                 ]);
+            }
+        } else {
+            Log::info('ExamPdfExportService: Chrome进程正常结束', [
+                'elapsed' => $elapsed . 's',
+                'exit_code' => $process->getExitCode(),
+                'pdf_exists' => $pdfExists,
+                'pdf_size' => $pdfSize
+            ]);
+        }
+
+        // 读取PDF内容
+        $pdfBinary = null;
+        if ($pdfExists && $pdfSize > 0) {
+            $pdfBinary = file_get_contents($tmpPdf);
+            Log::info('ExamPdfExportService: PDF读取成功', [
+                'size' => strlen($pdfBinary),
+                'elapsed' => $elapsed . 's'
+            ]);
+        } else {
+            Log::error('ExamPdfExportService: PDF文件不存在或为空', [
+                'tmp_pdf' => $tmpPdf,
+                'exists' => $pdfExists,
+                'size' => $pdfSize
+            ]);
+        }
+
+        // 【优化】确保资源正确释放,使用try-catch包装
+        try {
+            if ($pdfExists && file_exists($tmpPdf)) {
                 @unlink($tmpPdf);
+                Log::debug('ExamPdfExportService: 临时PDF文件已删除', ['path' => $tmpPdf]);
+            }
+        } catch (\Exception $e) {
+            Log::warning('ExamPdfExportService: 删除临时PDF文件失败', [
+                'path' => $tmpPdf,
+                'error' => $e->getMessage()
+            ]);
+        }
+
+        try {
+            if ($userDataDir && is_dir($userDataDir)) {
                 File::deleteDirectory($userDataDir);
-                return null;
+                Log::debug('ExamPdfExportService: Chrome用户数据目录已删除', ['path' => $userDataDir]);
             }
+        } catch (\Exception $e) {
+            Log::warning('ExamPdfExportService: 删除Chrome用户数据目录失败', [
+                'path' => $userDataDir,
+                'error' => $e->getMessage()
+            ]);
         }
 
-        $pdfBinary = $pdfExists ? file_get_contents($tmpPdf) : null;
-        @unlink($tmpPdf);
-        File::deleteDirectory($userDataDir);
         return $pdfBinary ?: null;
     }