• 记一次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/>');
        }
    
    }
  • 相关阅读:
    第二章、Java内存区域与内存溢出异常
    第二章、Java内存区域与内存溢出异常
    腾讯//格雷编码
    腾讯//格雷编码
    数据结构5.5_广义表的递归算法
    数据结构5.4_m元多项式的表示
    数据结构4.2_串操作应用举例_建立词索引表
    数据结构3_栈和队列
    数据结构2_线性表
    数据结构1_绪论
  • 原文地址:https://www.cnblogs.com/timseng/p/13019289.html
Copyright © 2020-2023  润新知