Laravel批量发送带附件通知异常问题求助
问题分析与解决方案
核心问题定位
withBatchId()调用报错:Bus::batch()中传入的任务实例无效(返回null),导致框架无法为任务绑定批量ID- 无批量任务记录 +
batching()返回false:未正确创建批量任务,通知类未关联到批量上下文,或者批量任务的创建逻辑错误
步骤1:修正CustomEmail通知类
确保Batchable trait正确集成,且通知类的队列逻辑与批量上下文关联:
<?php namespace App\Notifications; use Illuminate\Bus\Queueable; use Illuminate\Notifications\Notification; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Bus\Batchable; use Illuminate\Notifications\Messages\MailMessage; class CustomEmail extends Notification implements ShouldQueue { use Queueable, Batchable; public $content; public $attachment; public function __construct($content, $attachment = null) { $this->content = $content; $this->attachment = $attachment; } public function via($notifiable) { return ['mail']; } public function toMail($notifiable) { $message = (new MailMessage()) ->subject('自定义通知') ->line($this->content); // 添加附件(如果存在) if ($this->attachment) { $message->attach(storage_path('temp/'.$this->attachment->filename)); } return $message; } }
步骤2:修正EmailController中的批量任务创建逻辑
错误根源是未正确将通知发送包装为可批量的队列任务,正确写法是为每个收件人生成独立的通知任务,加入批量后再分发:
<?php namespace App\Http\Controllers; use Illuminate\Support\Facades\Bus; use App\Notifications\CustomEmail; use App\Models\User; use App\Models\Attachment; class EmailController extends Controller { public function sendBatchedNotifications() { // 1. 处理通知内容与附件 $content = request('content'); $attachment = null; if (request()->hasFile('attachment')) { $file = request()->file('attachment'); $tempPath = storage_path('temp'); $filename = uniqid().'.'.$file->getClientOriginalExtension(); $file->move($tempPath, $filename); // 创建Attachment模型,预留批量ID字段 $attachment = Attachment::create([ 'filename' => $filename, 'temp_path' => $tempPath, 'batch_id' => null, ]); } // 2. 获取收件人列表 $recipients = User::where('notifyable', true)->get(); // 3. 生成批量任务数组 $tasks = []; foreach ($recipients as $user) { // 为每个收件人创建独立的通知任务 $tasks[] = new CustomEmail($content, $attachment); } // 4. 创建并分发批量任务 if (!empty($tasks)) { $batch = Bus::batch($tasks) ->name('批量邮件通知') ->dispatch(); // 关联附件与批量ID if ($attachment) { $attachment->update(['batch_id' => $batch->id]); } } return redirect()->back()->with('success', '批量通知已开始发送'); } }
步骤3:修正NotificationSent事件监听逻辑
确保DeleteEmailAttachments处理器能正确识别批量完成状态,并关联附件的批量ID:
<?php namespace App\Listeners; use Illuminate\Notifications\Events\NotificationSent; use App\Models\Attachment; class DeleteEmailAttachments { public function handle(NotificationSent $event) { $notification = $event->notification; // 检查当前通知所属批量是否已完成 if ($notification->batching() && $notification->batch()->finished()) { $batchId = $notification->batch()->id; $attachment = Attachment::where('batch_id', $batchId)->first(); if ($attachment) { // 删除本地文件 @unlink($attachment->temp_path.'/'.$attachment->filename); // 删除数据库记录 $attachment->delete(); } } } }
关键注意事项
- 队列驱动配置:必须使用支持批量任务的队列驱动(如database、redis),sync驱动不支持批量功能
- Batchable trait使用:通知类必须引入
Batchabletrait,不能重写batch()方法,否则会丢失批量上下文 - 任务实例有效性:
Bus::batch()中传入的必须是有效的ShouldQueue任务实例,不能是null或非队列任务 - 事件监听逻辑:
NotificationSent事件在单条通知发送完成后触发,需通过batch()->finished()判断整个批量是否完成
内容的提问来源于stack exchange,提问作者rileys
相关产品推荐
相关产品推荐

