The environment

PHP_VERSION = 7.4 laravel/framework: ^ 7.0

A static variable

  • Many programming languages interpret static variables as having the same lifetime as the program and initializing them only once
  • But due to thePHPThe common running environment ofphp-fpmMode in which the process is reclaimed at the end of each request and static variables do not reside in memory (only for this request)
  • This is what the PHP website says

Another important feature of variable scopes is static variables. A static variable exists only in the local function domain, but its value is not lost when the program executes outside this scope. Consider the following example:
https://www.php.net/manual/zh/language.variables.scope.php

preface

  • The project has the following pseudocode logic: Because in the databasejson_dataIs ajsonString, so you don’t have to parse it every time you get itstaticThe variable modifier makes it unnecessary to parse again for the next access
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class AttributeRequestLog extends Model
{

    public function getJsonData($key)
    {
        static $jsonData;
        if (is_null($jsonData)) {
            $jsonData = json_decode($this->attributes['json_data'], true);
        }

        return $jsonData[$key] ?? null;
    }
}

Because I didn’t queue up to handle an asynchronous task, the program has been fine. Until one day after the queue, some colleagues feedback, there is abnormal data reported. After a quick check of the log, I found that there was a problem with the log dot data in the queue. Then I added more dots and finally found the location.

  • Due to theLaravelOf the queue usingCLIRun mode, this time processing tasks are running in the background
  • When the queue starts, the code is loaded and will not be updated until the queue process is killed.

Analysis of the source code

  • Queue startup command:php artisan queue:work
  • Find the startup filesrc\Illuminate\Queue\Console\WorkCommand.phpIt’s an inheritance fromIlluminate\Console\CommandClass, runartisanWill run itshandlemethods



  • It’s actually taking the driver of the queue and going toworkerTo run the task, pass a parameteronceWhether or not only one task is running, here we look directly at itdaemonmethods
  • Go to thesrc\Illuminate\Queue\Worker.phpthedaemonmethods

  • The first three lines of code listen for exit signals and then actively exit the process
  • The next line$lastRestartIs to retrieve a timestamp from the cache for later active exit processes. This timestamp will only be used by thephp artisan queue:restartreset
  • So you can usequeue:restartThis command to stop the queue process (does not automatically start the queue process, but can be usedSupervisorTo restart automatically.)
  • This is followed by an endless loop to keep the process from being killed
  • The first logical judgment depends on whether the program has been started in maintenance mode, forced to run, etc., which is the prejudgment of whether the queued task can continue processing
  • So we want to temporarily pause the queue process, we can send one to the processSIGUSR2When the queue process has finished processing the current task, it will stop the next time. When it wants to continue processing, it sends another oneSIGCONTsignal
  • And then togetNextJobThis method fetches the next task to be processed in the configured queue driver (Redis, Database, etc.)
  • If asynchronous scaling is supported,registerTimeoutHandlerDo something about the task timeout, if the task timeout, then end the task
  • Next, if no task is retrieved, the program will sleep. Otherwise, the task will run. Here you can see the actual running code of the task
  • So let’s go straight to thisfireMethod, and then find the corresponding queue-driven class that inherits from the parentfiremethods

  • It’s actually reflecting thisjobClass then calls its corresponding method
  • The last block of code before the loop is stopifNecessary to see if the process needs to terminate, and this is where Queue: Restart is handled


  • So when we use static variables, although each reflection instantiates a new onejobBut in factjobWhen I go to get the properties of the model,staticThe variable is always the same, which leads to what I said beforeBug

The original link https://www.shiguopeng.cn/archives/516