Laravel队列实现PDF合并后无法下载及邮件发送方案问询
方案1:队列完成后实现PDF下载
队列是异步执行逻辑,请求端触发任务时仅完成任务投递,不会等待任务执行完成,因此原同步逻辑里直接返回下载流的写法不适用异步场景,可按以下步骤改造:
- 先给业务关联表(此处对应筛查表)新增3个字段:
pdf_generated_status标记PDF生成状态(枚举值:pending/processed/failed)、final_pdf_path存储最终合并后PDF的存储路径、pdf_generated_at记录生成完成时间。 - 把现有PDF处理逻辑迁移到队列Job的
handle方法中,将原有download模式的保存逻辑改为存储到本地目录:
// 替换原有 $pdfMerger->save($screening_id.'.pdf', "download"); $finalPdfPath = 'screening/pdf/final-pdf/'.$screening_id.'.pdf'; $pdfMerger->save(storage_path('app/public/'.$finalPdfPath), "file"); // 存储完成后更新业务表状态 Screening::where('id', $screening_id)->update([ 'pdf_generated_status' => 'processed', 'final_pdf_path' => $finalPdfPath ]); // 可选:删除临时目录的两个原始PDF,节省存储空间 Storage::disk('public')->delete([ 'screening/pdf/'.$screening_id.'.pdf', 'screening/pdf/temporary-pdf/'.$screening_id.'.pdf' ]);
- 前端配合做轮询或者WebSocket通知:用户触发PDF生成请求后,前端每隔3-5秒请求后端查询对应筛查记录的生成状态,当状态变为
processed时,返回对应的下载入口给用户。 - 新增下载接口,验证状态后返回文件流:
public function downloadPdf(Screening $screening) { if ($screening->pdf_generated_status !== 'processed') { return response()->json(['msg' => 'PDF尚未生成完成,请稍后再试'], 400); } return Storage::disk('public')->download($screening->final_pdf_path); }
方案2:合并完成后直接发送邮件
无需用户等待,任务执行完成后自动触发邮件推送,实现更简单:
- 生成通知类:执行命令
php artisan make:notification ScreeningPdfReady - 在通知类的
toMail方法中配置邮件内容和附件:
public function toMail($notifiable) { return (new MailMessage) ->subject('您的筛查PDF报告已生成') ->line('附件为合并后的完整筛查报告,你也可以点击下方按钮下载:') ->action('下载报告', route('screening.pdf.download', $this->screening->id)) // 小于10M的PDF可直接作为附件发送,大文件建议只放下载链接避免邮件被拒收 ->attach(storage_path('app/public/'.$this->screening->final_pdf_path), [ 'as' => '筛查报告_'.$this->screening->id.'.pdf', 'mime' => 'application/pdf', ]); }
- 在队列Job的handle方法中,更新完业务表状态后触发邮件发送即可:
$screening->participant->notify(new ScreeningPdfReady($screening));
原有逻辑优化建议
- 替换
file_get_contents拉取远程PDF的逻辑,改用Laravel Http客户端,增加超时和重试机制,避免远程资源拉取失败导致任务报错:
$ecg_contents = Http::timeout(30)->retry(2)->get($ecg_link)->body();
- 队列启动时单独配置内存和超时参数,适配大PDF合并的资源需求:
php artisan queue:work --memory=1024 --timeout=120 - 给Job类增加重试次数配置
public $tries = 3,避免偶发网络波动、资源锁定导致的任务执行失败。
内容的提问来源于stack exchange,提问作者Ilhamzac
相关产品推荐
相关产品推荐

