zoukankan      html  css  js  c++  java
  • 记一次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/>');
        }
    
    }
  • 相关阅读:
    实验5
    实验4
    实验3
    《整数计算器》
    《写一个程序,用于分析一个字符串中各个单词出现的频率,并将单词和它出现的频率输出显示》
    《把一个英语句子中的单词次序颠倒后输出》
    个人简介
    学习《构建之法》的感想
    把一个英语句子中的单词次序颠倒后输出。例如输入“how are you”,输出“you are how”;
    写一个程序,用于分析一个字符串中各个单词出现的频率,并将单词和它出现的频率输出显示。(单词之间用空格隔开,如“Hello World My First Unit Test”);
  • 原文地址:https://www.cnblogs.com/timseng/p/13019289.html
Copyright © 2011-2022 走看看