"Error – Wkhtmltopdf failed (error code: -11). Memory limit too low or maximum file number of subprocess reached."

huangapple go评论84阅读模式
英文:

"Error - Wkhtmltopdf failed (error code: -11). Memory limit too low or maximum file number of subprocess reached."

问题

我在一个Odoo项目上工作,需要为1万条记录生成PDF报告。当我尝试打印包含大量记录的报告时,遇到以下错误:

> Wkhtmltopdf 失败(错误代码:-11)。内存限制太低或子进程的最大文件数已达到。消息:b''。

该错误发生在执行_run_wkhtmltopdf方法期间,该方法负责使用Wkhtmltopdf将HTML内容转换为PDF文档。

我注意到,只有当记录数量超过某个阈值时(大约1万条)才会发生错误。在此之下,报告会成功生成,没有任何问题。

我怀疑错误与资源限制有关,如内存或子进程限制。然而,我不确定如何解决这个问题并优化报告生成过程。

请问是否可以提供关于如何处理在Odoo中或通用地使用Wkhtmltopdf进行大规模报告生成的指导?是否有需要调整以避免此错误的特定设置或配置?此外,是否有关于分页或分批生成报告以避免资源限制的最佳做法?

def print_pdf(self):
    data = {
        'inner': self.sale_ids or self.env['sale.order.line'].search_read(
            [], ['salesman_id', 'product_id', 'name', 'price_unit',
                 'qty_to_deliver', 'price_subtotal', 'state'],
            limit=10000)}
    return self.env.ref('coc_bot.sale_order_report'). \
        report_action(self.sale_ids.ids or None, data=data)

XML:

<tr>
   <td t-out="da['salesman_id'][1] or ''"/>
   <td t-out="da['product_id'][1] or ''"/>
   <td t-out="da['name'] or ''"/>
   <td t-out="da['price_unit'] or ''"/>
   <td t-out="da['qty_to_deliver'] or ''"/>
   <td t-out="da['price_subtotal'] or ''"/>
   <td t-out="da['state'] or ''"/>
</tr>

这是引发错误的代码段:

try:

    wkhtmltopdf = [_get_wkhtmltopdf_bin()] + command_args + files_command_args + paths + [pdf_report_path]
    process = subprocess.Popen(wkhtmltopdf, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    out, err = process.communicate()
    print(process.returncode, 'process',wkhtmltopdf,'wkhtmltopdf',out,'-----------',  err[-1000:])
    if process.returncode not in [0, 1]:
        if process.returncode == -11:
            message = _(
                'Wkhtmltopdf failed (error code: %s). Memory limit too low or maximum file number of subprocess reached. Message : %s')
        else:
            message = _('Wkhtmltopdf failed (error code: %s). Message: %s')
        _logger.warning(message, process.returncode, err[-1000:])
        raise UserError(message % (str(process.returncode), err[-1000:]))
    else:
        if err:
            _logger.warning('wkhtmltopdf: %s' % err)
except:
    raise
英文:

I am working on an Odoo project where I need to generate PDF reports for 10 000 records. When I try to print a report with a high number of records, I encounter the following error:

> Wkhtmltopdf failed (error code: -11). Memory limit too low or maximum file number of subprocess reached. Message: b''.

The error occurs during the execution of the _run_wkhtmltopdf method, which is responsible for converting HTML content to a PDF document using Wkhtmltopdf.

I have noticed that the error only occurs when the number of records exceeds a certain threshold (around 10,000). Below that point, the report generates successfully without any issues.

I suspect that the error is related to resource limitations, such as memory or subprocess limits. However, I am unsure about how to address this problem and optimize the report generation process.

Could someone please provide guidance on how to handle large-scale report generation in Odoo or in general using Wkhtmltopdf? Are there any specific settings or configurations that need to be adjusted to avoid this error? Additionally, are there any best practices for pagination or generating reports in smaller batches to avoid resource limitations?

def print_pdf(self):
    data = {
        &#39;inner&#39;: self.sale_ids or self.env[&#39;sale.order.line&#39;].search_read(
            [], [&#39;salesman_id&#39;, &#39;product_id&#39;, &#39;name&#39;, &#39;price_unit&#39;,
                 &#39;qty_to_deliver&#39;, &#39;price_subtotal&#39;, &#39;state&#39;],
            limit=10000)}
    return self.env.ref(&#39;coc_bot.sale_order_report&#39;). \
        report_action(self.sale_ids.ids or None, data=data)

XML:

    &lt;tr&gt;
       &lt;td t-out=&quot;da[&#39;salesman_id&#39;][1] or &#39;&#39;&quot;/&gt;
       &lt;td t-out=&quot;da[&#39;product_id&#39;][1] or &#39;&#39;&quot;/&gt;
       &lt;td t-out=&quot;da[&#39;name&#39;] or &#39;&#39;&quot;/&gt;
       &lt;td t-out=&quot;da[&#39;price_unit&#39;] or &#39;&#39;&quot;/&gt;
       &lt;td t-out=&quot;da[&#39;qty_to_deliver&#39;] or &#39;&#39;&quot;/&gt;
       &lt;td t-out=&quot;da[&#39;price_subtotal&#39;] or &#39;&#39;&quot;/&gt;
       &lt;td t-out=&quot;da[&#39;state&#39;] or &#39;&#39;&quot;/&gt;
      &lt;/tr&gt;

This is the code from where the error is raised.

  try:

        wkhtmltopdf = [_get_wkhtmltopdf_bin()] + command_args + files_command_args + paths + [pdf_report_path]
        process = subprocess.Popen(wkhtmltopdf, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        out, err = process.communicate()
        print(process.returncode, &#39;process&#39;,wkhtmltopdf,&#39;wkhtmltopdf&#39;,out,&#39;-----------&#39;,  err[-1000:])
        if process.returncode not in [0, 1]:
            if process.returncode == -11:
                message = _(
                    &#39;Wkhtmltopdf failed (error code: %s). Memory limit too low or maximum file number of subprocess reached. Message : %s&#39;)
            else:
                message = _(&#39;Wkhtmltopdf failed (error code: %s). Message: %s&#39;)
            _logger.warning(message, process.returncode, err[-1000:])
            raise UserError(message % (str(process.returncode), err[-1000:]))
        else:
            if err:
                _logger.warning(&#39;wkhtmltopdf: %s&#39; % err)
    except:
        raise

答案1

得分: 1

  1. 通过使用systemd服务单元来运行Odoo,并添加以下行:
    LimitNOFILE=100000

    更改该值以解决您的文件打开限制问题。

    通常情况下,这是由于记录数量和模板大小导致的内存问题。这就是第二个解决方案发挥作用的时候。

  2. 找到一种方法将您的PDF文件分割成多个页面,以便您能够选择一个或多个记录,并使用那些记录的一部分创建一个PDF,然后将所有生成的小型PDF合并成一个单一的最终PDF文件。

    使用解决方案2,您将能够处理任何性能问题,生成PDF文件无论大小或需要处理多少记录来构建您的PDF文件。

英文:

Let me give you 2 possible solutions

  1. Run Odoo using systemd service unit and add this line:
    LimitNOFILE=100000

Change the value to address your limitations and that will play around the issue of the limit of open files.

Normally it's a memory issue due to number of records and the template size. That's when the second solution come into play

  1. Find a way to split your PDF into several pages allowing you to be able to pick one or more records and create a PDF with that chunk of records and merge all the generated small PDFs into a single and final one to return

With this solution 2 you will be able to handle any kind of performance issue generating a PDF no matter how big it is or how many records you have to handle to build your PDF

huangapple
  • 本文由 发表于 2023年7月20日 20:26:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/76729866.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定