Laravel 9异步Job执行时如何实时推送NoticeEvent通知?
Laravel 9队列任务实时推送Pusher进度通知方案
问题背景
在Laravel 9中实现了处理大量图片的ExchangeJob队列任务,通过NoticeEvent结合Pusher推送处理进度,但所有事件会被暂存至Job完成后才批量触发,无法实时接收进度通知。
相关代码
ExchangeJob类
class ExchangeJob implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; public function __construct() { } public function handle() { $ImageObject = new \App\Core\Images; $ImageObject->ProductsImagesRegenerate(); } }
ProductsImagesRegenerate方法
public function ProductsImagesRegenerate(): void { NoticeEvent::dispatch('Starting processing notice'); $images = array("red", "green", "blue", "yellow"); foreach ($images as $value) { NoticeEvent::dispatch($value); } event(new NoticeEvent("End processing images")); }
日志现象
执行php artisan queue:listen后,NoticeEvent全部在ExchangeJob完成后才执行:
2022-12-10 20:45:41 App\Jobs\ExchangeJob ........................... RUNNING 2022-12-10 20:45:55 App\Jobs\ExchangeJob .................. 13,073.61ms DONE 2022-12-10 20:45:55 App\Events\NoticeEvent ......................... RUNNING 2022-12-10 20:45:55 App\Events\NoticeEvent ................... 333.14ms DONE ...
解决方案
1. 配置事件监听器为异步队列
让NoticeEvent的监听器进入独立队列,确保事件能被即时消费:
- 修改
app/Providers/EventServiceProvider.php,注册事件与监听器:
protected $listen = [ \App\Events\NoticeEvent::class => [ \App\Listeners\NoticeEventListener::class, ], ];
- 让监听器实现
ShouldQueue接口,支持队列异步处理:
namespace App\Listeners; use App\Events\NoticeEvent; use Illuminate\Contracts\Queue\ShouldQueue; use Pusher\Pusher; class NoticeEventListener implements ShouldQueue { // 可指定专属队列,优先处理通知 public $queue = 'notifications'; public function handle(NoticeEvent $event) { // 执行Pusher推送逻辑 $pusher = new Pusher( config('broadcasting.connections.pusher.key'), config('broadcasting.connections.pusher.secret'), config('broadcasting.connections.pusher.app_id'), config('broadcasting.connections.pusher.options') ); $pusher->trigger('progress-channel', 'notice-event', [ 'message' => $event->message ]); } }
2. 调整事件分发方式
使用dispatchAfterResponse确保事件无需等待当前Job进程即可触发:
public function ProductsImagesRegenerate(): void { NoticeEvent::dispatchAfterResponse('Starting processing notice'); $images = array("red", "green", "blue", "yellow"); foreach ($images as $value) { NoticeEvent::dispatchAfterResponse($value); } NoticeEvent::dispatchAfterResponse("End processing images"); }
3. 检查队列核心配置
- 确保
.env中队列驱动非sync(建议用redis或database):
QUEUE_CONNECTION=redis
- 启动队列监听时,优先处理通知队列:
php artisan queue:listen --queue=notifications,default
4. 避免事务阻塞
若Job中包含数据库事务,需将事件分发放在事务外部,或使用DB::afterCommit确保事务提交后触发事件(如果业务允许):
// 事务内处理图片逻辑 DB::transaction(function () { // 图片处理操作 }); // 事务外分发进度事件 NoticeEvent::dispatch('当前批次处理完成');
内容的提问来源于stack exchange,提问作者Александр Инженер
相关产品推荐
相关产品推荐

