You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

生产环境中Puppeteer生成PDF超时问题求助

Puppeteer生成PDF在生产环境超时的问题分析

问题背景

以下C#代码使用PuppeteerSharp生成PDF,在测试和开发服务器运行正常,但生产服务器触发超时异常。

生成PDF的核心方法

public async Task<IActionResult> SavePDF(string content)
{
    try
    {
        var browser = await Puppeteer.LaunchAsync(new LaunchOptions
        {
            Headless = true,
        });

        var page = await browser.NewPageAsync();

        // Set a timeout (60 sec) while loading the content
        await page.SetContentAsync(content, new NavigationOptions { Timeout = 60000 });

        var fileName = $"C:/CustomerData/{Guid.NewGuid()}_{CompanyNumber}.pdf";
        await page.PdfAsync(fileName);

        // Dispose of the browser properly
        await browser.CloseAsync();

        return Json(fileName);
    }
    catch (Exception ex)
    {
        ASLog(ex);
        return Problem($"Error generating PDF: {ex.Message}");
    }
}

Program.cs初始化代码

// Download Chromium once when the application starts
await new BrowserFetcher().DownloadAsync();

生产环境错误栈

2025-03-27T00:44:03.4471493+00:00 80001bae-0000-f300-b63f-84710c7967bb [ERR] An unhandled exception has occurred while executing the request. (48a46595)
System.TimeoutException: Timeout of 180000 ms exceeded
at PuppeteerSharp.Helpers.TaskHelper.WithTimeout[T](Task1 task, TimeSpan timeout, Func2 exceptionFactory) in /home/runner/work/puppeteer-sharp/puppeteer-sharp/lib/PuppeteerSharp/Helpers/TaskHelper.cs:line 185
at PuppeteerSharp.Cdp.CdpCDPSession.SendAsync(String method, Object args, Boolean waitForCallback, CommandOptions options) in /home/runner/work/puppeteer-sharp/puppeteer-sharp/lib/PuppeteerSharp/Cdp/CdpCDPSession.cs:line 113
at PuppeteerSharp.CDPSession.SendAsync[T](String method, Object args, CommandOptions options) in /home/runner/work/puppeteer-sharp/puppeteer-sharp/lib/PuppeteerSharp/CDPSession.cs:line 48
at PuppeteerSharp.Cdp.CdpPage.PdfInternalAsync(String file, PdfOptions options) in /home/runner/work/puppeteer-sharp/puppeteer-sharp/lib/PuppeteerSharp/Cdp/CdpPage.cs:line 864
at PuppeteerSharp.Page.PdfStreamAsync(PdfOptions options) in /home/runner/work/puppeteer-sharp/puppeteer-sharp/lib/PuppeteerSharp/Page.cs:line 389
at ASWeb.Controllers.MainMenu.SalesInvoicing.SalesInvoicingController.SendEmailPDF(InvoicePDFViewModel model) in C:\Code\AS-Web\ASWeb.App\Controllers\MainMenu\SalesInvoicing\SalesInvoicingController.cs:line 2401
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at ASWeb.Middlewares.TrialVersionMiddleware.Invoke(HttpContext httpContext, ISharedService shared) in C:\Code\AS-Web\ASWeb.App\Middlewares\TrialVersionMiddleware.cs:line 39
at ASWeb.Middlewares.XeroDisconnectedMiddleware.Invoke(HttpContext httpContext, ISettingsService settings) in C:\Code\AS-Web\ASWeb.App\Middlewares\XeroDisconnectedMiddleware.cs:line 22
at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Program.<>c__DisplayClass0_0.<

$>b__9>d.MoveNext() in C:\Code\AS-Web\ASWeb.App\Program.cs:line 210
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddlewareImpl.g__Awaited|10_0(ExceptionHandlerMiddlewareImpl middleware, HttpContext context, Task task)

可能的原因分析

  • 生产环境资源不足:生产服务器CPU、内存资源紧张,Chromium渲染PDF需要较多系统资源,导致PdfAsync操作超时。建议检查生产服务器的资源使用率,尤其是PDF生成高峰期的负载情况。
  • Headless模式兼容性问题:默认的无头模式在无GUI的生产服务器上可能存在兼容性问题。可以尝试切换到新版无头模式,或添加沙箱禁用参数:
    var browser = await Puppeteer.LaunchAsync(new LaunchOptions
    {
        Headless = HeadlessMode.New,
        Args = new[] { "--no-sandbox", "--disable-setuid-sandbox", "--disable-dev-shm-usage" }
    });
    
  • Chromium完整性或版本问题:生产环境下载的Chromium可能因网络问题不完整,或版本与PuppeteerSharp不兼容。可手动指定Chromium路径,或重新下载确保文件完整。
  • 页面资源未完全加载:虽然设置了SetContentAsync的60秒超时,但如果内容包含大量远程资源(图片、样式),生产环境网络访问较慢会导致页面未完全渲染,进而引发PdfAsync超时。可调整超时时间并设置等待网络空闲:
    await page.SetContentAsync(content, new NavigationOptions 
    { 
        Timeout = 120000,
        WaitUntil = WaitUntilNavigation.Networkidle0 
    });
    
  • 并发请求阻塞:生产环境大量并发PDF生成请求,每个请求启动新Chromium实例会耗尽服务器资源,导致操作排队超时。建议使用浏览器池复用实例,减少资源消耗。
  • 文件系统权限问题:生成PDF到C:/CustomerData/目录时,生产环境应用程序池可能无写入权限,导致PdfAsync操作卡住超时。需检查该目录的读写权限,确保应用身份有足够权限。

内容的提问来源于stack exchange,提问作者Pedro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 14:13:17