記一次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 App\Console\Commands;

use App\Jobs\TestCJob;
use Illuminate\Console\Command;

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 App\Jobs;

use Exception;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Artisan;

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 . "\n", 8);
    }
    /**
     * 任務失敗的處理過程
     *
     * @param  Exception  $exception
     * @return void
     */
    public function failed(Exception $exception)
    {
        file_put_contents('testcitemfail.log', json_encode($exception->getMessage()) . "\n", 8);
        // 給用戶發送任務失敗的通知,等等……
    }

}

 

TestCItem

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;

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/>');
    }

}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM