artur-graniszewski/ZEUS-for-PHP

View on GitHub
src/Zeus/Kernel/ProcessManager/Scheduler/Discipline/LruDiscipline.php

Summary

Maintainability
A
1 hr
Test Coverage
<?php

namespace Zeus\Kernel\ProcessManager\Scheduler\Discipline;

use Zeus\Kernel\ProcessManager\Config;
use Zeus\Kernel\ProcessManager\Scheduler\ProcessCollection;
use Zeus\Kernel\ProcessManager\Status\ProcessState;

class LruDiscipline implements DisciplineInterface
{
    /**
     * @param Config $config
     * @param ProcessCollection $processes
     * @return \mixed[]
     */
    public function manage(Config $config, ProcessCollection $processes)
    {
        $result = [
            'create' => 0,
            'terminate' => [],
            'soft_terminate' => [],
        ];

        if (!$config->isProcessCacheEnabled()) {
            return $result;
        }

        $statusSummary = $processes->getStatusSummary();
        $processesToTerminate = $this->getProcessesToTerminate($processes, $config, $statusSummary);
        $processesToCreate = $this->getAmountOfProcessesToCreate($processes, $config, $statusSummary);

        return [
            'create' => $processesToCreate,
            'terminate' => [],
            'soft_terminate' => $processesToTerminate,
        ];
    }

    /**
     * @param ProcessCollection $processes
     * @param Config $config
     * @param int[] $statusSummary
     * @return int|mixed
     */
    protected function getAmountOfProcessesToCreate(ProcessCollection $processes, Config $config, array $statusSummary)
    {
        $idleProcesses = $statusSummary[ProcessState::WAITING];
        $allProcesses = $processes->count();

        // start additional processes, if number of them is too small.
        if ($idleProcesses < $config->getMinSpareProcesses()) {
            $idleProcessSlots = $processes->getSize() - $processes->count();

            return min($idleProcessSlots, $config->getMinSpareProcesses() - $idleProcesses);
        }

        if ($allProcesses === 0 && $config->getMinSpareProcesses() === 0 && $config->getMaxSpareProcesses() > 0) {

            return $config->getMaxSpareProcesses();
        }

        return 0;
    }

    /**
     * @param ProcessCollection $processes
     * @param Config $config
     * @param int[] $statusSummary
     * @return int[]
     */
    protected function getProcessesToTerminate(ProcessCollection $processes, Config $config, array $statusSummary)
    {
        $expireTime = microtime(true) - $config->getProcessIdleTimeout();

        $processesToTerminate = [];
        $idleProcesses = $statusSummary[ProcessState::WAITING];
        //$busyProcesses = $statusSummary[ProcessState::RUNNING];
        //$terminatedProcesses = $statusSummary[ProcessStatus::STATUS_EXITING] + $statusSummary[ProcessStatus::STATUS_KILL];

        // terminate idle processes, if number of them is too high.
        if ($idleProcesses > $config->getMaxSpareProcesses()) {
            $toTerminate = $idleProcesses - $config->getMaxSpareProcesses();
            $spareProcessesFound = 0;

            foreach ($processes as $pid => $processStatus) {
                if (!ProcessState::isIdle($processStatus)) {
                    continue;
                }

                if ($processStatus['time'] < $expireTime) {
                    $processesToTerminate[$processStatus['time']] = $pid;
                    ++$spareProcessesFound;

                    if ($spareProcessesFound === $toTerminate) {
                        break;
                    }
                }
            }

            ksort($processesToTerminate, SORT_ASC);
            $processesToTerminate = array_slice($processesToTerminate, 0, $toTerminate);
        }

        return $processesToTerminate;
    }
}