在 Laravel 中,队列任务执行不彻底的排查分析

1、安装一个主题,是基于队列实现的。代码如下

    /**
     * Execute the job.
     *
     * @return void
     */    public function handle()
    {
        // 判断 原始主题ID 是否为空,为空则为安装主题,否则为复制主题
        if (empty($this->themeInstallationTask->themeInstallation->original_theme_id)) {
            // 下载 ZIP
            $downloadZipRes = $this->downloadZip();

            // 解压缩 ZIP
            self::$absolutePath = $downloadZipRes['absolutePath'];
            $this->unzip($downloadZipRes['destination']);

            // 执行安装命令
            self::$destination = $downloadZipRes['destination'];
            $this->execInstallationCommand($this->themeInstallationTask->themeInstallation->theme_id);

        } else {
            // 复制主题文件
            $this->copyThemeAsset();
        }

        // 同步主题的素材至CDN
        $this->syncThemeAssetCdn($this->themeInstallationTask->themeInstallation->theme_id);

        $this->themeInstallationTask->themeInstallation->processing = ThemeInstallation::PROCESSING_FALSE;
        $this->themeInstallationTask->themeInstallation->processing_failed = ThemeInstallation::PROCESSING_FAILED_FALSE;

        $this->themeInstallationTask->themeInstallationVersionPreset->processing = ThemeInstallationVersionPreset::PROCESSING_FALSE;
        $this->themeInstallationTask->themeInstallationVersionPreset->processing_failed = ThemeInstallationVersionPreset::PROCESSING_FAILED_FALSE;

        $this->themeInstallationTask->processing = ThemeInstallationTask::PROCESSING_FALSE;
        $this->themeInstallationTask->processing_failed = ThemeInstallationTask::PROCESSING_FAILED_FALSE;

        $this->themeInstallationTask->push();

        event(new ThemeCreated($this->themeInstallationTask->themeInstallation->theme));

    }

2、基于初步的分析结论,在执行至 同步主题的素材至CDN 时,感觉程序的运行就突然中断了似的。表现出的现状。如图1

图1

3、感觉就像是容器在执行至 同步主题的素材至CDN 时,容器重启了。进而导致程序的运行中断。决定在本地环境模拟一下。决定在执行至 同步主题的素材至CDN 时,添加 sleep(60)。

    /**
     * 同步主题的素材至CDN
     *
     * @param string $themeId 主题 ID
     * @return void
     */    private function syncThemeAssetCdn($themeId)
    {
        $this->themeInstallationTask->step = ThemeInstallationTask::STEP_SYNC_THEME_ASSET_CDN;
        $this->themeInstallationTask->save();

        // 程序开始的地方

        app(ExecCommandHandler::class)->syncThemeAssetCdn($themeId);

        sleep(60);

        // 程序结束的地方,中途未抛出异常
    }

4、模拟的方案一的流程是,当在执行至 sleep(60) 时,中断队列任务的运行,手动让队列处理器停止运行。如图2

图2

PS E:\wwwroot\object> php artisan queue:work
[2022-08-04 13:57:07][tnFIT28iqbv67GpZ2xwzP6hRFEaJJ6vh] Processing: Modules\ThemeStoreDB\Jobs\ThemeInstallationJob
PS E:\wwwroot\object>

5、模拟的方案一,确定在中断队列任务的运行后,在执行至 同步主题的素材至CDN 时,程序的后续流程不会再执行。其最终表现与步骤一一致。然后再次开始 php artisan queue:work,确认队列任务已经丢失。如图3

图3

6、模拟的方案二的流程是,当在执行至 sleep(60) 时,手动停止 PHP 程序的运行。如图4

图4

PS C:\Windows\system32> php-cgi.exe -b 127.0.0.1:9001-c C:/php-7.4.27/php.ini
PS C:\Windows\system32>

7、模拟的方案二,确定在停止 PHP 程序的运行后,在执行至 同步主题的素材至CDN 时,程序的后续流程不会再执行。其最终表现与步骤一一致。但是如果此时 php artisan queue:work 一直运行中的话,当开始 PHP 程序的运行后,队列任务仍然能够继续执行完毕。

8、针对此问题的临时解决方案为:重新发起一次新的队列任务。后续再想办法彻底解决。

永夜