You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 06:42:02