Odoo万级记录PDF报表生成遇Wkhtmltopdf(-11)错误求助
解决Odoo大规模报表生成时Wkhtmltopdf报错问题
一、调整系统与Wkhtmltopdf配置
针对错误提示的内存/子进程限制问题,先从基础配置入手优化:
- 增加Wkhtmltopdf内存配额:在Odoo调用Wkhtmltopdf的参数中添加
--memory-size 2048(单位MB,可根据服务器配置调整),提升其可用内存上限。可修改Odoo的report模块中_run_wkhtmltopdf方法的command_args列表,加入该参数。 - 放宽系统资源限制:
- 临时调整Odoo运行用户的文件句柄限制:执行
ulimit -n 4096(需重启Odoo生效) - 永久配置:在
/etc/security/limits.conf中添加:odoo soft nofile 4096 odoo hard nofile 8192
- 临时调整Odoo运行用户的文件句柄限制:执行
- 更新Wkhtmltopdf版本:旧版本存在内存泄漏问题,升级至与当前Odoo版本兼容的最新稳定版(如0.12.6)。
二、分批生成并合并PDF(最佳实践)
直接生成10000条记录的超大HTML会耗尽内存,核心解决方案是拆分批次生成后合并:
代码实现示例
import base64 import io from PyPDF2 import PdfMerger def print_pdf(self): batch_size = 1000 # 可根据服务器性能调整 sale_lines = self.sale_ids or self.env['sale.order.line'].search( [], ['salesman_id', 'product_id', 'name', 'price_unit', 'qty_to_deliver', 'price_subtotal', 'state']) total_batches = (len(sale_lines) + batch_size - 1) // batch_size merger = PdfMerger() # 分批生成PDF并合并 for batch_num in range(total_batches): start = batch_num * batch_size end = start + batch_size batch_data = {'inner': sale_lines[start:end].read([ 'salesman_id', 'product_id', 'name', 'price_unit', 'qty_to_deliver', 'price_subtotal', 'state' ])} # 渲染单批次PDF pdf_content, _ = self.env.ref('coc_bot.sale_order_report').render_qweb_pdf( res_ids=None, data=batch_data) merger.append(io.BytesIO(pdf_content)) # 生成合并后的PDF附件并返回下载链接 merged_buffer = io.BytesIO() merger.write(merged_buffer) merged_buffer.seek(0) attachment = self.env['ir.attachment'].create({ 'name': '批量销售订单报表.pdf', 'datas': base64.b64encode(merged_buffer.getvalue()), 'type': 'binary' }) return { 'type': 'ir.actions.act_url', 'url': f'web/content/?model=ir.attachment&id={attachment.id}&filename_field=name&field=datas&download=true&filename=批量销售订单报表.pdf', 'target': 'new', }
注意:需先安装
PyPDF2库(pip install PyPDF2)
三、优化报表HTML结构
- 添加分页CSS:在报表XML模板中加入分页样式,避免Wkhtmltopdf因处理超长表格耗尽内存:
<style> table { page-break-inside: avoid; } tr { page-break-inside: avoid; } .page-break { page-break-after: always; } </style> - 简化DOM元素:移除模板中不必要的嵌套标签、冗余样式,减少HTML解析时的内存占用。
四、Odoo内部逻辑优化
- 避免一次性加载全量数据:原代码中
search_read一次性读取10000条记录,改为分批读取减少内存占用。 - 启用异步任务:若报表生成耗时较长,使用Odoo的
queue_job模块将生成任务放入后台队列,避免阻塞前端界面。
五、错误排查补充
- 查看系统内核日志(如
/var/log/syslog),确认是否存在OOM(内存不足)或进程资源耗尽的详细记录。 - 逐步调整批次大小,找到服务器能稳定处理的最大单批次记录数。
内容的提问来源于stack exchange,提问作者Abhin k
相关产品推荐
相关产品推荐

