记录一次wkhtmltopdf生成pdf造成oom问题

发布于:2025-05-30 ⋅ 阅读:(17) ⋅ 点赞:(0)

问题现象

有个生成pdf的接口,到处pdf为空;docker环境必现,但是本地环境无法复现

1、代码增加各处错误判断,发现docker环境调用接口出现

Loading pages (1/6)
[>                                                           ] 0%
[======>                                                     ] 10%
[======================>                                     ] 37%
[========================>                                   ] 41%
[==============================>                             ] 50%
[====================================>                       ] 61%
[======================================================>     ] 90%
signal: killed

2、查看docker系统日志

dmesg|grep "kill"

发现oom

查看资料后显示wkhtmltopdf创建pdf会造成高内存分配

优化pdf参数,问题得到解决

// Configure PDF generator with memory-saving options
    pdfg, err := wkhtmltopdf.NewPDFGenerator()
    if err != nil {
        return nil, fmt.Errorf("PDF generator initialization failed: %w", err)
    }

    pdfg.PageSize.Set(wkhtmltopdf.PageSizeA4)
    pdfg.Dpi.Set(96) // 1、设置dpi,降低内存使用
    pdfg.NoCollate.Set(true)  // Disable collation to reduce memory
    pdfg.Grayscale.Set(false)
    
    // Configure page with memory optimization settings
    page := wkhtmltopdf.NewPageReader(r)
    page.LoadErrorHandling.Set("ignore")
    page.JavascriptDelay.Set(2000) // Allow time for JS to execute
    pdfg.AddPage(page)

    // Set environment variables for memory constraints
    os.Setenv("QTWEBKIT_SETTINGS", "MaximumPages=1") //2、限制同时处理的页数,避免内存峰值
    os.Setenv("QTWEBKIT_MAX_MEMORY", "256M") // Limit WebKit memory usage

    // Create PDF with timeout
    // 3、增加超时判断
    pdfCtx, pdfCancel := context.WithTimeout(context.Background(), 5*time.Minute)
    defer pdfCancel()

    errChan := make(chan error, 1)
    go func() {
        defer close(errChan)
        errChan <- pdfg.Create()
    }()

    select {
    case err := <-errChan:
        if err != nil {
            return nil, fmt.Errorf("PDF generation failed: %w", err)
        }
    case <-pdfCtx.Done():
        return nil, fmt.Errorf("PDF generation timed out")
    }

    // Return the generated PDF
    return pdfg.Bytes(), nil