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

如何在Laravel Worker创建与销毁时执行事件,管理Puppeteer浏览器?

Laravel Worker生命周期中管理Puppeteer浏览器实例的方案

一、用Laravel原生Worker事件实现需求

Laravel自带Worker启动和停止的事件,完全可以对应你动态创建/销毁Puppeteer浏览器的需求:

1. 监听Worker启动事件初始化浏览器

监听Illuminate\Queue\Events\WorkerStarting事件,在Worker进程启动时创建专属的Puppeteer浏览器实例,绑定到当前进程的容器中(每个Worker是独立进程,容器实例不共享,不用担心冲突)。

2. 监听Worker停止事件关闭浏览器

监听Illuminate\Queue\Events\WorkerStopping事件,在Worker被Horizon回收时,取出该进程的浏览器实例并关闭,释放资源。

代码实现示例

首先在EventServiceProvider中注册事件监听:

// app/Providers/EventServiceProvider.php
protected $listen = [
    \Illuminate\Queue\Events\WorkerStarting::class => [
        \App\Listeners\BootPuppeteerBrowser::class,
    ],
    \Illuminate\Queue\Events\WorkerStopping::class => [
        \App\Listeners\ShutdownPuppeteerBrowser::class,
    ],
];

然后创建启动浏览器的监听器:

// app/Listeners/BootPuppeteerBrowser.php
namespace App\Listeners;

use Illuminate\Queue\Events\WorkerStarting;
use Illuminate\Support\Facades\App;
use Puppeteer;

class BootPuppeteerBrowser
{
    public function handle(WorkerStarting $event)
    {
        // 启动Puppeteer,根据你的需求调整参数
        $browser = Puppeteer::launch([
            'headless' => 'new',
            'args' => ['--no-sandbox', '--disable-setuid-sandbox'],
            // 可添加内存限制等参数,避免资源过载
        ]);

        // 将浏览器实例绑定到当前Worker进程的容器
        App::instance('puppeteer.browser', $browser);
    }
}

再创建关闭浏览器的监听器:

// app/Listeners/ShutdownPuppeteerBrowser.php
namespace App\Listeners;

use Illuminate\Queue\Events\WorkerStopping;
use Illuminate\Support\Facades\App;

class ShutdownPuppeteerBrowser
{
    public function handle(WorkerStopping $event)
    {
        // 取出当前进程的浏览器实例并关闭
        $browser = App::get('puppeteer.browser');
        if ($browser) {
            $browser->close();
        }
    }
}

之后在队列任务中,直接从容器取出浏览器实例使用即可:

// 示例队列任务
public function handle()
{
    $browser = app('puppeteer.browser');
    $page = $browser->newPage();
    
    // 执行你的爬虫/页面操作
    
    $page->close(); // 任务完成后关闭页面,避免内存泄漏
}

二、思路合理性分析

你的思路完全没问题,核心是让每个Worker进程持有独立的Puppeteer浏览器实例,避免多任务共享浏览器导致的状态污染、内存泄漏等问题,完美适配Horizon动态扩缩容Worker的场景。

需要注意几个细节:

  • 调整Puppeteer启动参数,比如添加内存限制相关配置,避免Worker数量达到上限时服务器资源耗尽
  • 处理Worker异常崩溃的情况:如果Worker意外退出,WorkerStopping事件可能无法触发,建议在任务的finally块中关闭当前页面,同时依赖操作系统的进程资源回收机制清理残留的浏览器进程
  • 不要在任务间复用Page实例,每个任务创建新Page并及时关闭,减少内存占用

对比你提到的方案:

  • puppeteer-cluster需要额外的队列调度逻辑,和Laravel原生队列架构冲突,没必要引入
  • puppeteer-pool已过时,稳定性无法保证,基于Worker生命周期的方案更贴合Laravel生态,维护成本更低

内容的提问来源于stack exchange,提问作者Clayton Gray

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 05:12:34