记一次Laravel Job 异步队列 调用Artisan::call构造函数赋值导致的问题

先说下bug背景,以下是调用链:

调用链

  php版本7.1

laraavel版本5.5

 说明下运行流程A:通过调用TestC artisan command或者接口用dispatch方法将TestCJob放入异步队列,TestCJob通过handle方法调用Artisan::call运行TestCItem,最后这个TestCItem在构造方法中初始化一些变量如runtime,在运行时打印runtime

注意注意注意,这里就出现问题了

首先重启队列(让Job生效)

第一种使用场景:运行流程A的时候,TestCItem handel的时候打印的runtime是重启队列的时间,以后的每个Job调用TestCItem的handle都是打印的重启队列的时间

第二种使用场景:直接通过命令行执行TestCItem时handle,但是这时打印的是执行时间

 以下是运行日志:

 重启Job队列时会打印一次,之后再执行流程A就不会进入构造函数且runtime是构造函数时间

 

直接运行TestCItem命令行则每次都会进入TestCItem的构造函数

这就会造成问题在流程A中runtime和一些其他的在构造函数里设置的值每次运行不是最新的,

回想下Laravel的架构就会发现问题所在:

这里Artisan::call向laravel的容器中注入了一个Artisan Command,所以触发了构造函数,之后每次运行时就直接使用注入的对象,所以之前初始化的runtime就是对象构造时候的时间

所以在Laravel中组合使用Job队列和ArtisanCommand时要注意,千万不要使用构造函数赋值(你将得到Job队列重启时的赋值),应该在handle中赋值使用。

 以下是各个类:

TestC
<?php

namespace AppConsoleCommands;

use AppJobsTestCJob;
use IlluminateConsoleCommand;

class TestC extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'testc';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'testc';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $this->output('---脚本开始---');
        dispatch(new TestCJob('xxxxx'))->onConnection('redis');
        $this->output('---脚本结束---');
    }

    /**
     * @param $msg
     * @param bool $showTime
     * @param bool $isCli
     */
    public function output($msg, $showTime = true, $isCli = true)
    {
        echo ($showTime ? date('Y-m-d H:i:s') . ' ' : '') . $msg . ($isCli ? PHP_EOL : '<br/>');
    }

}

TestCJob

<?php

namespace AppJobs;

use Exception;
use IlluminateBusQueueable;
use IlluminateContractsQueueShouldQueue;
use IlluminateFoundationBusDispatchable;
use IlluminateQueueInteractsWithQueue;
use IlluminateQueueSerializesModels;
use IlluminateSupportFacadesArtisan;

class TestCJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    /**
     * 任务可以尝试的最大次数。
     *
     * @var int
     */
    public $tries = 3;

    /**
     * 任务可以执行的最大秒数 (超时时间)。
     *
     * @var int
     */
    public $timeout = 120;
    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct()
    {
    }
    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        $re = 1;
        $re = Artisan::call('testcitem');
        file_put_contents('testcitem.log', '$re' . $re . "
", 8);
    }
    /**
     * 任务失败的处理过程
     *
     * @param  Exception  $exception
     * @return void
     */
    public function failed(Exception $exception)
    {
        file_put_contents('testcitemfail.log', json_encode($exception->getMessage()) . "
", 8);
        // 给用户发送任务失败的通知,等等……
    }

}

TestCItem

<?php

namespace AppConsoleCommands;

use IlluminateConsoleCommand;

class TestCItem extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'testcitem';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'testcitem';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
        $this->runtime = date('Y-m-d H:i:s');
        $this->output('---TestCItem---__construct');
    }

    private $runtime = 0;
    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $this->output('---handle---' . $this->runtime);
        return 0;
    }

    /**
     * @param $msg
     * @param bool $showTime
     * @param bool $isCli
     */
    public function output($msg, $showTime = true, $isCli = true)
    {
        echo ($showTime ? date('Y-m-d H:i:s') . ' ' : '') . $msg . ($isCli ? PHP_EOL : '<br/>');
    }

}
原文地址:https://www.cnblogs.com/timseng/p/13019289.html