On the Horizon

Horizon is the Laravel author’s complement to Queue, providing a friendly UI and Supervisor process management


Start the

`php artisan horizon`
Copy the code

Complete structure

The complete structure of Horizon in Redis is explained later.

The source code parsing

This is the source code that was triggered when we launched Horizon, marking 6 areas for analysis

public function handle(MasterSupervisorRepository $masters)
{
    if ($masters->find(MasterSupervisor::name())) {
        return $this->comment('A master supervisor is already running on this machine.'); 1} ️ ⃣$master = (new MasterSupervisor)->handleOutputUsing(function ($type.$line) {
        $this->output->write($line); }); 2 ️ ⃣ ProvisioningPlan: : get (MasterSupervisor: : name () - > deploy ($this->option('environment')?? config('horizon.env')?? config('app.env')); 3 ️ ⃣$this->info('Horizon started successfully.');

    pcntl_async_signals(true); 4 ️ ⃣ pcntl_signal (SIGINT,function () use ($master) {
        $this->line('Shutting down... ');

        return $master->terminate(); }); 5 ️ ⃣$master->monitor(); 6 ️ ⃣}Copy the code

Six pieces of code analysis

  • 1️ one here is the generation of onegethostname() + Str::random(4)MasterProcess name. If a process with the same name is created, an error message ~ is returned

  • 2️ initialize the MasterSupervisor object

    $this->name ($this->name)

    If ($this->supervisors) {if ($this->supervisors)

    $this->output ($this->output)

    The last step is to refresh, refresh high clearly the horizon in this picture: master: gethostname () + Str: : random (4) the process name

    $this->connection()->del(‘commands:’.$name);

    That’s what it does, go to Redis and delete this key.


  • 3️ discount over four LEVELS

    Create a resource allocation plan!

    The Horizon configuration file contains parameters such as the number of processes, the balance process allocation policy, and so on

    This is what is parsed through the ProvisioningPlan class.

    🏁 here we parse its corresponding method

    ProvisioningPlan::get(MasterSupervisor::name()) This is equivalent to obtaining an object with the specified configuration file and process 'name'.Copy the code

    Then,

    (new ProvisioningPlan)->deploy($this->option('environment')?? config('horizon.env') ?? config('app.env') );Copy the code

    Deploys the configuration of the specified environment. The purpose of this code is to rpush all subsequent instructions to Redis first.

    In effect, you perform the following steps to save the parameters to Redis

    The code in the figure above does not create this data immediately, but rather ephemerates the associated create instructions to Redis.

    To Redis format is, variable on behalf of the name of the machine: ‘commands: master: gethostname () + Str: : random (4)’ : json_encode ($options] [AddSupervisor: : class,)

    The $options as shown in figure

    Save operations and configurations toRedis, after the execution of the time can be found out all relevant data generation corresponding process!

    🏁 Start confirmation

    Execute PHP Artisan Horizon to see the changes in Redis

    If it weren’t for the DD (), the data would be consumed immediately!

    It is safe to assume that this is the process to be created!

    At this point, you must be wondering when Horizon will consume the data in Redis and then generate the corresponding process. This is going to continue to look back!


  • 4️ here is nothing good to talk about, after PHP7.1, there is a new signal processing function: pCNTL_async_signals, return or set whether asynchronous signal processing.


  • 5️ one signal on terminate is registered here and the function is to close the process. For example, we send this signal when we press Command + C on the Mac Os. Let’s take a quick look at how to shut down all processes. The implementation will be covered later.


  • 6️ one is the core part

    • $this – > ensureNoOtherMasterSupervisors (), make sure whether there is a process of the same name, if any, will throw an exception.

    • $this->listenForSignals() registers the signal to be processed

    • $this->persist() ¶

    • $this->loop() to start the process.

    • $this->processPendingCommands();This business is going fromRedisRetrieve the data you just saved

    • Start the process.$this->monitorSupervisors()

    The above supervisors have a lot of information, followed by the circular supervisors.

    Execute Symfony\Component\Process()->start() to start the supervisors’ sub-processes.

    Then execute the command in the commandLine, as follows

    • After the startup is complete, print the local process and see the same command as just executed


conclusion

The data about the process to be started is saved to the MasterSupervisor object in various ways, and the process is created based on the data in the object.

The Process is terminated, paused, and restarted through the PCNTL extension to implement the listener signal implementation, Process creation through Symfony\Component\Process start() method

Implement.