Dompdf在由Laravel的队列工作进程调用时会卡住,无法将包含大量行和图片的表格转换成PDF
我使用一个配合Dompdf的 PHP脚本,从数据库拉取X 条数据,将它们整理成X 行表格,然后从本地文件系统加载X 张图片并将它们转换成一个PDF文件。虽然X 较小时(测试到最多9),这样的设定似乎运作良好。但是当我把X 设为18进行测试时,如果脚本是从命令行执行,是可以工作的。该脚本大约需要1 ~ 1.5分钟,峰值内存使用量小于30M。如果把脚本放入Laravel队列中,排队的作业总是超时。
我已经尝试将作业 timeout 增加到900s,将队列 retry_after 增加到1800s,确保 OPcache 已启用,以及 opcache.memory_consumption=512,如Dompdf的 文档 所建议。以上都不起作用。
我当前的服务器环境是:Ubuntu 24.04、PHP 8.3、Laravel v12.56、Dompdf v3.1.5。几乎相同的脚本在X = 18、Laravel v6、PHP v7.4时能够工作,但在Laravel升级到v12、PHP升级到v8.3之后似乎就不再工作了。
我也尝试切换到Spatie的 Browsershot。Browsershot在将同一份包含18行表格和18张图片的PDF模板转换时似乎略微更快,但最终的PDF似乎没有正确应用所有CSS样式,且无法正确渲染页码。此外,当Browsershot从队列工作进程中调用时,会出现以下异常。因此目前Browsershot似乎不是一个可行的前进路径。
有人能否给出一些高层次的思路,帮助我着手解决这个问题?
[2026-05-10 00:11:09] production.ERROR: The command "PATH=$PATH:/usr/local/bin:/opt/homebrew/bin NODE_PATH=`npm root -g` "node" 'vendor/spatie/browsershot/src/../bin/browser.cjs' '{"url":"file:\/\/\/tmp\/>
Exit Code: 127(Command not found)
Working directory: /
Output:
================
Error Output:
================
sh: 1: npm: not found
sh: 1: node: not found
{"exception":"[object] (Symfony\\Component\\Process\\Exception\\ProcessFailedException(code: 0): The command \"PATH=$PATH:/usr/local/bin:/opt/homebrew/bin NODE_PATH=`npm root -g` \"node\" 'vendor/spatie/>
解决方案
问题最终仍然是作业超时时间设置得不够长。一旦我在分派作业的应用服务器上为 public $timeout = 300; 设置了相应值,整个设置又重新开始正常工作。
我忽略的一点是,超时是在作业被分派时设定的,而不是在队列工作进程执行作业时设定的。我的理解是,当作业被分派时,Laravel只会把最少的信息(作业类和实例化作业类所需的参数)保存到队列驱动中。然后队列工作进程会用这些最少信息重新实例化作业并执行它。但事实证明我的理解是错误的。队列工作进程其实只是从队列驱动取出作业,按原样执行。
这个微妙的差异通常在队列工作进程与分派作业的服务器在同一台机器时并不成问题,但当队列工作进程在另一台服务器上运行且在作业分派后再调整超时时,就会成为问题。在这种情况下,队列工作服务器上设置的任何超时都不会生效。我吸取了教训,希望我的错误能在未来为他人省下点时间。