|
|
@@ -1270,13 +1270,11 @@ class ExamPdfExportService
|
|
|
|
|
|
$process = new Process([
|
|
|
$chromeBinary,
|
|
|
- '--headless',
|
|
|
+ '--headless=new',
|
|
|
'--disable-gpu',
|
|
|
'--no-sandbox',
|
|
|
'--disable-setuid-sandbox',
|
|
|
'--disable-dev-shm-usage',
|
|
|
- '--no-zygote',
|
|
|
- '--disable-features=VizDisplayCompositor',
|
|
|
'--disable-software-rasterizer',
|
|
|
'--disable-extensions',
|
|
|
'--disable-background-networking',
|
|
|
@@ -1299,44 +1297,66 @@ class ExamPdfExportService
|
|
|
'--disable-backgrounding-occluded-windows',
|
|
|
'--disable-renderer-backgrounding',
|
|
|
'--disable-features=AudioServiceOutOfProcess',
|
|
|
+ '--disable-gpu-rasterization',
|
|
|
+ '--disable-web-security',
|
|
|
+ '--disable-features=VizDisplayCompositor',
|
|
|
+ '--font-render-hinting=none',
|
|
|
'--user-data-dir=' . $userDataDir,
|
|
|
'--print-to-pdf=' . $tmpPdf,
|
|
|
'--print-to-pdf-no-header',
|
|
|
'--allow-file-access-from-files',
|
|
|
+ '--virtual-time-budget=10000',
|
|
|
+ '--run-all-compositor-stages-before-draw',
|
|
|
'file://' . $htmlPath,
|
|
|
], null, [
|
|
|
'HOME' => $runtimeHome,
|
|
|
'XDG_RUNTIME_DIR' => $runtimeXdg,
|
|
|
]);
|
|
|
|
|
|
- // 【修复】减少超时时间,避免队列任务整体超时
|
|
|
- // 队列任务默认60秒超时,给Chrome进程设置45秒超时
|
|
|
- $process->setTimeout(45);
|
|
|
+ // 【修复】进一步缩短超时时间,提高响应速度
|
|
|
+ // 设置30秒超时,快速失败避免长时间等待
|
|
|
+ $process->setTimeout(30);
|
|
|
$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
|
|
|
+ 'timeout' => 30,
|
|
|
+ 'html_size' => file_exists($htmlPath) ? filesize($htmlPath) : 0
|
|
|
]);
|
|
|
|
|
|
$process->start();
|
|
|
$pdfGenerated = false;
|
|
|
|
|
|
- // 【修复】缩短轮询时间,提高响应速度
|
|
|
+ // 【修复】进一步缩短轮询时间,提高响应速度
|
|
|
$pollStart = microtime(true);
|
|
|
- $maxPollSeconds = 40; // 缩短到40秒(小于Chrome超时45秒)
|
|
|
- $checkInterval = 100_000; // 100ms检查一次
|
|
|
+ $maxPollSeconds = 28; // 缩短到28秒(小于Chrome超时30秒)
|
|
|
+ $checkInterval = 50_000; // 50ms检查一次(更频繁)
|
|
|
+
|
|
|
+ // 初始等待1秒让Chrome启动
|
|
|
+ usleep(1_000_000);
|
|
|
|
|
|
while ($process->isRunning() && (microtime(true) - $pollStart) < $maxPollSeconds) {
|
|
|
+ // 每2秒输出一次进度
|
|
|
+ $currentElapsed = microtime(true) - $pollStart;
|
|
|
+ if (fmod($currentElapsed, 2) < 0.1 || $currentElapsed < 0.2) {
|
|
|
+ Log::debug('ExamPdfExportService: Chrome渲染中', [
|
|
|
+ 'elapsed' => round($currentElapsed, 2) . 's',
|
|
|
+ 'pdf_exists' => file_exists($tmpPdf),
|
|
|
+ 'pdf_size' => file_exists($tmpPdf) ? filesize($tmpPdf) : 0
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+
|
|
|
if (file_exists($tmpPdf) && filesize($tmpPdf) > 0) {
|
|
|
$pdfGenerated = true;
|
|
|
+ $elapsed = microtime(true) - $startedAt;
|
|
|
Log::info('ExamPdfExportService: PDF文件已生成,提前终止Chrome', [
|
|
|
- 'elapsed' => round(microtime(true) - $startedAt, 2) . 's',
|
|
|
- 'pdf_size' => filesize($tmpPdf)
|
|
|
+ 'elapsed' => round($elapsed, 2) . 's',
|
|
|
+ 'pdf_size' => filesize($tmpPdf),
|
|
|
+ 'poll_elapsed' => round($currentElapsed, 2) . 's'
|
|
|
]);
|
|
|
- $process->stop(2, $killSignal);
|
|
|
+ $process->stop(1, $killSignal);
|
|
|
break;
|
|
|
}
|
|
|
usleep($checkInterval);
|
|
|
@@ -1347,15 +1367,17 @@ class ExamPdfExportService
|
|
|
'elapsed' => round($elapsed, 2) . 's',
|
|
|
'is_running' => $process->isRunning(),
|
|
|
'pdf_exists' => file_exists($tmpPdf),
|
|
|
- 'pdf_size' => file_exists($tmpPdf) ? filesize($tmpPdf) : 0
|
|
|
+ 'pdf_size' => file_exists($tmpPdf) ? filesize($tmpPdf) : 0,
|
|
|
+ 'timeout' => $maxPollSeconds
|
|
|
]);
|
|
|
|
|
|
- // 【优化】强制停止Chrome进程
|
|
|
+ // 【优化】强制快速停止Chrome进程
|
|
|
if ($process->isRunning()) {
|
|
|
Log::warning('ExamPdfExportService: Chrome进程仍在运行,强制停止', [
|
|
|
- 'elapsed' => round($elapsed, 2) . 's'
|
|
|
+ 'elapsed' => round($elapsed, 2) . 's',
|
|
|
+ 'reason' => 'timeout'
|
|
|
]);
|
|
|
- $process->stop(2, $killSignal);
|
|
|
+ $process->stop(1, $killSignal);
|
|
|
}
|
|
|
|
|
|
$process->wait();
|
|
|
@@ -1364,10 +1386,11 @@ class ExamPdfExportService
|
|
|
Log::error('ExamPdfExportService: Chrome进程超时', [
|
|
|
'timeout' => $e->getExceededTimeout(),
|
|
|
'elapsed' => round(microtime(true) - $startedAt, 2) . 's',
|
|
|
- 'html_size' => file_exists($htmlPath) ? filesize($htmlPath) : 0
|
|
|
+ 'html_size' => file_exists($htmlPath) ? filesize($htmlPath) : 0,
|
|
|
+ 'message' => 'Chrome渲染超时,已自动终止'
|
|
|
]);
|
|
|
if ($process->isRunning()) {
|
|
|
- $process->stop(2, $killSignal);
|
|
|
+ $process->stop(1, $killSignal);
|
|
|
}
|
|
|
return $this->handleChromeProcessResult($tmpPdf, $userDataDir, $process, $startedAt);
|
|
|
} catch (ProcessSignaledException $e) {
|
|
|
@@ -1376,7 +1399,7 @@ class ExamPdfExportService
|
|
|
'elapsed' => round(microtime(true) - $startedAt, 2) . 's'
|
|
|
]);
|
|
|
if ($process->isRunning()) {
|
|
|
- $process->stop(2, $killSignal);
|
|
|
+ $process->stop(1, $killSignal);
|
|
|
}
|
|
|
return $this->handleChromeProcessResult($tmpPdf, $userDataDir, $process, $startedAt);
|
|
|
} catch (\Throwable $e) {
|
|
|
@@ -1386,7 +1409,7 @@ class ExamPdfExportService
|
|
|
'trace' => $e->getTraceAsString()
|
|
|
]);
|
|
|
if ($process->isRunning()) {
|
|
|
- $process->stop(2, $killSignal);
|
|
|
+ $process->stop(1, $killSignal);
|
|
|
}
|
|
|
return $this->handleChromeProcessResult($tmpPdf, $userDataDir, $process, null);
|
|
|
}
|