XWX-AI Claude Opus 4.6 commited on
Commit
78a0140
·
1 Parent(s): 7ff2703

fix: dynamic timeout for Puppeteer PDF generation

Browse files

Replace fixed timeouts with dynamic calculation based on image count
and total image size to prevent TimeoutError on large PDF exports

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Files changed (1) hide show
  1. server.js +30 -5
server.js CHANGED
@@ -74,6 +74,28 @@ app.post('/api/generate_pdf', async (req, res) => {
74
  const sizeWaitTime = imgSizeMB > 0 ? Math.min(imgSizeMB * 100, 3000) : 0;
75
  const totalWaitTime = Math.min(baseWaitTime + sizeWaitTime, 8000);
76
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  console.log(`[PDF-GEN] [${getElapsed()}] 正在启动浏览器...`);
78
  browser = await puppeteer.launch({
79
  executablePath: '/usr/bin/chromium',
@@ -91,14 +113,16 @@ app.post('/api/generate_pdf', async (req, res) => {
91
  console.log(`[PDF-GEN] [${getElapsed()}] 浏览器启动成功`);
92
 
93
  const page = await browser.newPage();
 
94
  await page.setViewport({ width: 1200, height: 800 });
 
95
 
96
  console.log(`[PDF-GEN] [${getElapsed()}] 正在填充页面内容...`);
97
- await page.setContent(htmlToUse, {
98
  waitUntil: ['load', 'networkidle0'],
99
- timeout: 120000
100
  });
101
- await page.waitForNetworkIdle({ idleTime: 500 });
102
  console.log(`[PDF-GEN] [${getElapsed()}] 页面内容加载完成`);
103
 
104
  // 等待 base64 图片完全渲染(检测实际加载状态)
@@ -158,7 +182,7 @@ app.post('/api/generate_pdf', async (req, res) => {
158
  });
159
  }
160
 
161
- return {
162
  initial: results,
163
  final: finalResults,
164
  total: images.length
@@ -208,7 +232,7 @@ app.post('/api/generate_pdf', async (req, res) => {
208
 
209
  // 根据 GitHub Issue #10341:截图可以强制触发渲染流水线
210
  console.log(`[PDF-GEN] [${getElapsed()}] 截图强制渲染(Issue #10341 workaround)...`);
211
- await page.screenshot({ type: 'png' });
212
  console.log(`[PDF-GEN] [${getElapsed()}] 截图完成`);
213
  } else {
214
  console.log(`[PDF-GEN] [${getElapsed()}] 无图片,等待 DOM 稳定...`);
@@ -216,6 +240,7 @@ app.post('/api/generate_pdf', async (req, res) => {
216
  }
217
 
218
  console.log(`[PDF-GEN] [${getElapsed()}] 正在生成 PDF 二进制流...`);
 
219
  const pdfBuffer = await page.pdf({
220
  format: 'A4',
221
  printBackground: true,
 
74
  const sizeWaitTime = imgSizeMB > 0 ? Math.min(imgSizeMB * 100, 3000) : 0;
75
  const totalWaitTime = Math.min(baseWaitTime + sizeWaitTime, 8000);
76
 
77
+ // 动态计算 waitForNetworkIdle 超时上限
78
+ const baseTimeout = 30000;
79
+ let extraMs = 0;
80
+ if (imgCount <= 30) {
81
+ extraMs = imgCount * 3000;
82
+ } else if (imgCount <= 50) {
83
+ extraMs = 90000 + (imgCount - 30) * 10000;
84
+ } else if (imgCount <= 100) {
85
+ extraMs = 290000 + (imgCount - 50) * 7000;
86
+ } else {
87
+ extraMs = 640000 + (imgCount - 100) * 5600;
88
+ }
89
+ const sizeExtraMs = (imgSizeMB || 0) * 3000;
90
+ const networkTimeout = Math.min(baseTimeout + extraMs + sizeExtraMs, 1200000);
91
+
92
+ // 动态计算 setContent 超时上限(setContent 需要解析 HTML + 加载资源)
93
+ const setContentTimeout = Math.min(60000 + extraMs + sizeExtraMs, 600000);
94
+
95
+ // 动态计算截图超时上限
96
+ const screenshotTimeout = Math.min(30000 + (imgCount > 0 ? extraMs / 10 : 0), 120000);
97
+
98
+ console.log(`[PDF-GEN] [${getElapsed()}] 动态超时: setContent=${(setContentTimeout / 1000).toFixed(0)}s, waitForNetworkIdle=${(networkTimeout / 1000).toFixed(0)}s`);
99
  console.log(`[PDF-GEN] [${getElapsed()}] 正在启动浏览器...`);
100
  browser = await puppeteer.launch({
101
  executablePath: '/usr/bin/chromium',
 
113
  console.log(`[PDF-GEN] [${getElapsed()}] 浏览器启动成功`);
114
 
115
  const page = await browser.newPage();
116
+ // 设置 viewport 满足大部分页面渲染需求
117
  await page.setViewport({ width: 1200, height: 800 });
118
+ console.log(`[PDF-GEN] [${getElapsed()}] Viewport: 1200x800`);
119
 
120
  console.log(`[PDF-GEN] [${getElapsed()}] 正在填充页面内容...`);
121
+ await page.setContent(htmlToUse, {
122
  waitUntil: ['load', 'networkidle0'],
123
+ timeout: setContentTimeout
124
  });
125
+ await page.waitForNetworkIdle({ idleTime: 500, timeout: networkTimeout });
126
  console.log(`[PDF-GEN] [${getElapsed()}] 页面内容加载完成`);
127
 
128
  // 等待 base64 图片完全渲染(检测实际加载状态)
 
182
  });
183
  }
184
 
185
+ return {
186
  initial: results,
187
  final: finalResults,
188
  total: images.length
 
232
 
233
  // 根据 GitHub Issue #10341:截图可以强制触发渲染流水线
234
  console.log(`[PDF-GEN] [${getElapsed()}] 截图强制渲染(Issue #10341 workaround)...`);
235
+ await page.screenshot({ type: 'png', timeout: screenshotTimeout });
236
  console.log(`[PDF-GEN] [${getElapsed()}] 截图完成`);
237
  } else {
238
  console.log(`[PDF-GEN] [${getElapsed()}] 无图片,等待 DOM 稳定...`);
 
240
  }
241
 
242
  console.log(`[PDF-GEN] [${getElapsed()}] 正在生成 PDF 二进制流...`);
243
+
244
  const pdfBuffer = await page.pdf({
245
  format: 'A4',
246
  printBackground: true,