Spamworldpro Mini Shell
Spamworldpro


Server : Apache
System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64
User : corals ( 1002)
PHP Version : 7.4.33
Disable Function : exec,passthru,shell_exec,system
Directory :  /home/corals/old/vendor/magento/module-deploy/Process/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/corals/old/vendor/magento/module-deploy/Process/Queue.php
<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
declare(strict_types=1);

namespace Magento\Deploy\Process;

use Magento\Deploy\Package\Package;
use Magento\Deploy\Service\DeployPackage;
use Magento\Framework\App\ResourceConnection;
use Magento\Framework\App\State as AppState;
use Magento\Framework\Locale\ResolverInterface as LocaleResolver;
use Psr\Log\LoggerInterface;

/**
 * Deployment Queue
 *
 * Deploy packages in parallel forks (if available)
 */
class Queue
{
    /**
     * Default max amount of processes
     */
    const DEFAULT_MAX_PROCESSES_AMOUNT = 4;

    /**
     * Default max execution time
     */
    const DEFAULT_MAX_EXEC_TIME = 900;

    /**
     * @var array
     */
    private $packages = [];

    /**
     * @var int[]
     */
    private $processIds = [];

    /**
     * @var Package[]
     */
    private $inProgress = [];

    /**
     * @var int
     */
    private $maxProcesses;

    /**
     * @var int
     */
    private $maxExecTime;

    /**
     * @var AppState
     */
    private $appState;

    /**
     * @var LocaleResolver
     */
    private $localeResolver;

    /**
     * @var ResourceConnection
     */
    private $resourceConnection;

    /**
     * @var LoggerInterface
     */
    private $logger;

    /**
     * @var DeployPackage
     */
    private $deployPackageService;

    /**
     * @var array
     */
    private $options = [];

    /**
     * @var int
     */
    private $start = 0;

    /**
     * @var int
     */
    private $lastJobStarted = 0;

    /**
     * @var int
     */
    private $logDelay;

    /**
     * @param AppState $appState
     * @param LocaleResolver $localeResolver
     * @param ResourceConnection $resourceConnection
     * @param LoggerInterface $logger
     * @param DeployPackage $deployPackageService
     * @param array $options
     * @param int $maxProcesses
     * @param int $maxExecTime
     */
    public function __construct(
        AppState $appState,
        LocaleResolver $localeResolver,
        ResourceConnection $resourceConnection,
        LoggerInterface $logger,
        DeployPackage $deployPackageService,
        array $options = [],
        $maxProcesses = self::DEFAULT_MAX_PROCESSES_AMOUNT,
        $maxExecTime = self::DEFAULT_MAX_EXEC_TIME
    ) {
        $this->appState = $appState;
        $this->localeResolver = $localeResolver;
        $this->resourceConnection = $resourceConnection;
        $this->logger = $logger;
        $this->deployPackageService = $deployPackageService;
        $this->options = $options;
        $this->maxProcesses = $maxProcesses;
        $this->maxExecTime = $maxExecTime;
    }

    /**
     * Adds deployment package.
     *
     * @param Package $package
     * @param Package[] $dependencies
     * @return bool true on success
     */
    public function add(Package $package, array $dependencies = [])
    {
        $this->packages[$package->getPath()] = [
            'package' => $package,
            'dependencies' => $dependencies
        ];

        return true;
    }

    /**
     * Returns packages array.
     *
     * @return Package[]
     */
    public function getPackages()
    {
        return $this->packages;
    }

    /**
     * Process jobs
     *
     * @return int
     * @throws TimeoutException
     */
    public function process()
    {
        $returnStatus = 0;
        $this->logDelay = 10;
        $this->start = $this->lastJobStarted = time();
        $packages = $this->packages;
        while (count($packages) && $this->checkTimeout()) {
            foreach ($packages as $name => $packageJob) {
                // Unsets each member of $packages array (passed by reference) as each is executed
                $this->assertAndExecute($name, $packages, $packageJob);
            }

            $this->refreshStatus();

            if ($this->isCanBeParalleled()) {
                // in parallel mode sleep before trying to check status and run new jobs
                // phpcs:ignore Magento2.Functions.DiscouragedFunction
                usleep(500000); // 0.5 sec (less sleep == less time waste)

                foreach ($this->inProgress as $name => $package) {
                    if ($this->isDeployed($package)) {
                        unset($this->inProgress[$name]);
                    }
                }
            }
        }

        $this->awaitForAllProcesses();

        if (!empty($packages)) {
            throw new TimeoutException('Not all packages are deployed.');
        }

        return $returnStatus;
    }

    /**
     * Refresh current status in console once in 10 iterations (once in 5 sec)
     *
     * @return void
     */
    private function refreshStatus(): void
    {
        if ($this->logDelay >= 10) {
            $this->logger->info('.');
            $this->logDelay = 0;
        } else {
            $this->logDelay++;
        }
    }

    /**
     * Check that all depended packages deployed and execute
     *
     * @param string $name
     * @param array $packages
     * @param array $packageJob
     * @return void
     */
    private function assertAndExecute($name, array &$packages, array $packageJob)
    {
        /** @var Package $package */
        $package = $packageJob['package'];
        $dependenciesNotFinished = false;
        if ($package->getParent() && $package->getParent() !== $package) {
            foreach ($packageJob['dependencies'] as $dependencyName => $dependency) {
                if (!$this->isDeployed($dependency)) {
                    //If it's not present in $packages then it's already
                    //in progress so just waiting...
                    if (!array_key_exists($dependencyName, $packages)) {
                        $dependenciesNotFinished = true;
                    } else {
                        $this->assertAndExecute(
                            $dependencyName,
                            $packages,
                            $packages[$dependencyName]
                        );
                    }
                }
            }
        }
        $this->executePackage($package, $name, $packages, $dependenciesNotFinished);
    }

    /**
     * Executes deployment package.
     *
     * @param Package $package
     * @param string $name
     * @param array $packages
     * @param bool $dependenciesNotFinished
     * @return void
     */
    private function executePackage(Package $package, string $name, array &$packages, bool $dependenciesNotFinished)
    {
        if (!$dependenciesNotFinished
            && !$this->isDeployed($package)
            && ($this->maxProcesses < 2 || (count($this->inProgress) < $this->maxProcesses))
        ) {
            unset($packages[$name]);
            $this->execute($package);
        }
    }

    /**
     * Need to wait till all processes finished
     *
     * @return void
     */
    private function awaitForAllProcesses()
    {
        while ($this->inProgress && $this->checkTimeout()) {
            foreach ($this->inProgress as $name => $package) {
                if ($this->isDeployed($package)) {
                    unset($this->inProgress[$name]);
                }
            }

            $this->refreshStatus();

            // sleep before checking parallel jobs status
            // phpcs:ignore Magento2.Functions.DiscouragedFunction
            usleep(500000); // 0.5 sec (less sleep == less time waste)
        }
        if ($this->isCanBeParalleled()) {
            // close connections only if ran with forks
            $this->resourceConnection->closeConnection();
        }
    }

    /**
     * Checks if can be parallel.
     *
     * @return bool
     */
    private function isCanBeParalleled()
    {
        return function_exists('pcntl_fork') && $this->maxProcesses > 1;
    }

    /**
     * Executes the process.
     *
     * @param Package $package
     * @return bool true on success for main process and exit for child process
     * @throws \RuntimeException
     */
    private function execute(Package $package)
    {
        $this->lastJobStarted = time();
        $this->logger->info(
            "Execute: " . $package->getPath(),
            [
                'process' => $package->getPath(),
                'count' => count($package->getFiles()),
            ]
        );

        $this->appState->emulateAreaCode(
            $package->getArea() == Package::BASE_AREA ? 'global' : $package->getArea(),
            function () use ($package) {
                // emulate application locale needed for correct file path resolving
                $this->localeResolver->setLocale($package->getLocale());

                // execute package pre-processors
                // (may add more files to deploy, so it needs to be executed in main thread)
                foreach ($package->getPreProcessors() as $processor) {
                    $processor->process($package, $this->options);
                }
            }
        );

        if ($this->isCanBeParalleled()) {
            // phpcs:ignore Magento2.Functions.DiscouragedFunction
            $pid = pcntl_fork();
            if ($pid === -1) {
                throw new \RuntimeException('Unable to fork a new process');
            }

            if ($pid) {
                $this->inProgress[$package->getPath()] = $package;
                $this->processIds[$package->getPath()] = $pid;
                return true;
            }

            // process child process
            $this->inProgress = [];
            $this->deployPackageService->deploy($package, $this->options, true);
            // phpcs:ignore Magento2.Security.LanguageConstruct.ExitUsage
            exit(0);
        } else {
            $this->deployPackageService->deploy($package, $this->options);
            return true;
        }
    }

    /**
     * Checks if package is deployed.
     *
     * @param Package $package
     * @return bool
     */
    private function isDeployed(Package $package)
    {
        if ($this->isCanBeParalleled()) {
            if ($package->getState() === null) {
                $pid = $this->getPid($package);

                // When $pid comes back as null the child process for this package has not yet started; prevents both
                // hanging until timeout expires (which was behaviour in 2.2.x) and the type error from strict_types
                if ($pid === null) {
                    return false;
                }

                // phpcs:ignore Magento2.Functions.DiscouragedFunction
                $result = pcntl_waitpid($pid, $status, WNOHANG);
                if ($result === $pid) {
                    $package->setState(Package::STATE_COMPLETED);
                    // phpcs:ignore Magento2.Functions.DiscouragedFunction
                    $exitStatus = pcntl_wexitstatus($status);

                    $this->logger->info(
                        "Exited: " . $package->getPath() . "(status: $exitStatus)",
                        [
                            'process' => $package->getPath(),
                            'status' => $exitStatus,
                        ]
                    );

                    unset($this->inProgress[$package->getPath()]);
                    // phpcs:ignore Magento2.Functions.DiscouragedFunction
                    return pcntl_wexitstatus($status) === 0;
                } elseif ($result === -1) {
                    // phpcs:ignore Magento2.Functions.DiscouragedFunction
                    $errno = pcntl_errno();
                    // phpcs:ignore Magento2.Functions.DiscouragedFunction
                    $strerror = pcntl_strerror($errno);

                    throw new \RuntimeException(
                        "Error encountered checking child process status (PID: $pid): $strerror (errno: $errno)"
                    );
                }
                return false;
            }
        }
        return $package->getState();
    }

    /**
     * Returns process ID or null if not found.
     *
     * @param Package $package
     * @return int|null
     */
    private function getPid(Package $package)
    {
        return $this->processIds[$package->getPath()] ?? null;
    }

    /**
     * Checks timeout.
     *
     * @return bool
     */
    private function checkTimeout()
    {
        return time() - $this->lastJobStarted < $this->maxExecTime;
    }

    /**
     * Free resources
     *
     * Protect against zombie process
     *
     * @throws \RuntimeException
     * @SuppressWarnings(PHPMD.UnusedLocalVariable)
     * @return void
     */
    public function __destruct()
    {
        foreach ($this->inProgress as $package) {
            $pid = $this->getPid($package);
            $this->logger->info(
                "Reaping child process: {$package->getPath()} (PID: $pid)",
                [
                    'process' => $package->getPath(),
                    'pid' => $pid,
                ]
            );

            // phpcs:ignore Magento2.Functions.DiscouragedFunction
            if (pcntl_waitpid($pid, $status) === -1) {
                // phpcs:ignore Magento2.Functions.DiscouragedFunction
                $errno = pcntl_errno();
                // phpcs:ignore Magento2.Functions.DiscouragedFunction
                $strerror = pcntl_strerror($errno);

                throw new \RuntimeException(
                    "Error encountered waiting for child process (PID: $pid): $strerror (errno: $errno)"
                );
            }
        }
    }
}

Spamworldpro Mini