[ Mini Kiebo ]
Server: Windows NT DESKTOP-5B8S0D4 6.2 build 9200 (Windows 8 Professional Edition) i586
Path:
D:
/
Backup
/
05122024
/
htdocs
/
jurnal-kesmas
/
lib
/
pkp
/
classes
/
queue
/
[
Home
]
File: JobRunner.php
<?php declare(strict_types=1); /** * @file classes/queue/JobRunner.php * * Copyright (c) 2014-2022 Simon Fraser University * Copyright (c) 2000-2022 John Willinsky * Distributed under the GNU GPL v3. For full terms see the file docs/COPYING. * * @class JobRunner * * @brief Synchronous job runner that will attempt to execute jobs at the end of web request * life cycle. It class is designed to execute jobs when not running via a worker * or a cron job. */ namespace PKP\queue; use Illuminate\Database\Eloquent\Builder as EloquentBuilder; use PKP\config\Config; use PKP\core\PKPQueueProvider; class JobRunner { /** * The core queue job running service provider */ protected PKPQueueProvider $jobQueue; /** * Should have max job number running constrain */ protected bool $hasMaxJobsConstrain = false; /** * Max jobs to process in a single run */ protected ?int $maxJobsToProcess = null; /** * Should have max run time constrain when processing jobs */ protected bool $hasMaxExecutionTimeConstrain = false; /** * Max job processing run time in SECOND */ protected ?int $maxTimeToProcessJobs = null; /** * Should have max consumed memory constrain when processing jobs */ protected bool $hasMaxMemoryConstrain = false; /** * Max memory to consume when processing jobs in BYTE */ protected ?int $maxMemoryToConsumed = null; /** * Should estimate next job possible processing time to allow next job to be processed/run */ protected bool $hasEstimatedTimeToProcessNextJobConstrain = false; /** * Create a new instance * */ public function __construct(PKPQueueProvider $jobQueue = null) { $this->jobQueue = $jobQueue ?? app('pkpJobQueue'); } /** * Set the max job number running constrain * */ public function withMaxJobsConstrain(): self { $this->hasMaxJobsConstrain = true; if (! $this->getMaxJobsToProcess()) { $this->setMaxJobsToProcess(Config::getVar('queues', 'job_runner_max_jobs', 30)); } return $this; } /** * Set the max allowed jobs number to process * */ public function setMaxJobsToProcess(int $maxJobsToProcess): self { $this->maxJobsToProcess = $maxJobsToProcess; return $this; } /** * Get the max allowed jobs number to process * */ public function getMaxJobsToProcess(): ?int { return $this->maxJobsToProcess; } /** * Set the max run time constrain when processing jobs * */ public function withMaxExecutionTimeConstrain(): self { $this->hasMaxExecutionTimeConstrain = true; if (! $this->getMaxTimeToProcessJobs()) { $this->setMaxTimeToProcessJobs($this->deduceSafeMaxExecutionTime()); } return $this; } /** * Set the max allowed run time to process jobs in SECONDS * */ public function setMaxTimeToProcessJobs(int $maxTimeToProcessJobs): self { $this->maxTimeToProcessJobs = $maxTimeToProcessJobs; return $this; } /** * Get the max allowed run time to process jobs in SECONDS * */ public function getMaxTimeToProcessJobs(): ?int { return $this->maxTimeToProcessJobs; } /** * Set the max consumable memory constrain when processing jobs * */ public function withMaxMemoryConstrain(): self { $this->hasMaxMemoryConstrain = true; if (! $this->getMaxMemoryToConsumed()) { $this->setMaxMemoryToConsumed($this->deduceSafeMaxAllowedMemory()); } return $this; } /** * Set the max allowed consumable memory to process jobs in BYTES * */ public function setMaxMemoryToConsumed(int $maxMemoryToConsumed): self { $this->maxMemoryToConsumed = $maxMemoryToConsumed; return $this; } /** * get the max allowed consumable memory to process jobs in BYTES * */ public function getMaxMemoryToConsumed(): ?int { return $this->maxMemoryToConsumed; } /** * Set constrain to estimate next job possible processing time to allow next job to be processed/run * */ public function withEstimatedTimeToProcessNextJobConstrain(): self { $this->hasEstimatedTimeToProcessNextJobConstrain = true; return $this; } /** * Process/Run/Execute jobs off CLI * */ public function processJobs(EloquentBuilder $jobBuilder = null): bool { $jobBuilder ??= $this->jobQueue->getJobModelBuilder(); $jobProcessedCount = 0; $jobProcessingStartTime = time(); while ($jobBuilder->count()) { if ($this->exceededJobLimit($jobProcessedCount)) { return true; } if ($this->exceededTimeLimit($jobProcessingStartTime)) { return true; } if ($this->exceededMemoryLimit()) { return true; } if ($this->mayExceedMemoryLimitAtNextJob($jobProcessedCount, $jobProcessingStartTime)) { return true; } $this->jobQueue->runJobInQueue(); $jobProcessedCount = $jobProcessedCount + 1; } return true; } /** * Check if max job has processed or not * * @param int $jobProcessedCount The number of jobs that has processed so far */ protected function exceededJobLimit(int $jobProcessedCount): bool { if (! $this->hasMaxJobsConstrain) { return false; } return $jobProcessedCount >= $this->getMaxJobsToProcess(); } /** * Check if max run time to process jobs has exceed or not * * @param int $jobProcessingStartTime The start time since job processing has started in seconds */ protected function exceededTimeLimit(int $jobProcessingStartTime): bool { if (! $this->hasMaxExecutionTimeConstrain) { return false; } return (time() - $jobProcessingStartTime) >= $this->getMaxTimeToProcessJobs(); } /** * Check if memory consumed since job processing started has exceed defined max memory * */ protected function exceededMemoryLimit(): bool { if (! $this->hasMaxMemoryConstrain) { return false; } return memory_get_usage(true) >= $this->getMaxMemoryToConsumed(); } /** * Estimate if next job processing time will likely exceed defined max processing run time * * @param int $jobProcessedCount The number of jobs that has processed so far * @param int $jobProcessingStartTime The start time since job processing has started in seconds * */ protected function mayExceedMemoryLimitAtNextJob(int $jobProcessedCount, int $jobProcessingStartTime): bool { if (! $this->hasEstimatedTimeToProcessNextJobConstrain) { return false; } // if no max run time constrain set, no point in estimating the likely time exceed if (!$this->hasMaxExecutionTimeConstrain) { return false; } // if no job has processed yet, no way to calculate next job possible processing time if ($jobProcessedCount <= 0) { return false; } $currentTotalExecutionTime = time() - $jobProcessingStartTime; $timePerJob = (int)($currentTotalExecutionTime / $jobProcessedCount); $totalTimeByNextJobComplete = $currentTotalExecutionTime + ($timePerJob * 3); return $totalTimeByNextJobComplete > $this->getMaxTimeToProcessJobs(); } /** * Deduce possible safe max job processing run time in SECONDS * * It will consider both what defined in the ini file and application config file * and will take a minimum one based on those two values * */ protected function deduceSafeMaxExecutionTime(): int { $maxExecutionTimeSetToINI = (int)ini_get('max_execution_time'); $maxExecutionTimeSetToConfig = (int)Config::getVar('queues', 'job_runner_max_execution_time', 20); return $maxExecutionTimeSetToINI <= 0 ? $maxExecutionTimeSetToConfig : min($maxExecutionTimeSetToINI, $maxExecutionTimeSetToConfig); } /** * Deduce possible safe max consumable memory for job processing in BYTES * * It will consider both of what defined in the ini file and the application config file * and will take a minimum one based on those two values * * In the application config file, max memory can be defined as INT or STRING value in following manner * * If defined as INT (e.g 90), it will be calculated as percentage value of * what currently defined in the ini file. * * If defined as STRING (e.g 128M), it will try to calculate it as memory defined in megabytes * but if failed, will try to cast to INT to apply percentage rule * */ protected function deduceSafeMaxAllowedMemory(): int { $maxMemoryLimitSetToINI = function_exists('ini_get') ? ini_get('memory_limit') : '128M'; if (!$maxMemoryLimitSetToINI || -1 === $maxMemoryLimitSetToINI || '-1' === $maxMemoryLimitSetToINI) { $maxMemoryLimitSetToINI = '128M'; // Unlimited, set to 128M. } $maxMemoryLimitSetToINIInBytes = convertHrToBytes($maxMemoryLimitSetToINI); $maxMemoryLimitSetToConfig = Config::getVar('queues', 'job_runner_max_memory', 80); $maxMemoryLimitSetToConfigInBytes = in_array(strtolower(substr((string)$maxMemoryLimitSetToConfig, -1)), ['k', 'm', 'g'], true) ? convertHrToBytes($maxMemoryLimitSetToConfig) : (int)($maxMemoryLimitSetToINIInBytes * ((float)((int)$maxMemoryLimitSetToConfig / 100))); return min($maxMemoryLimitSetToConfigInBytes, $maxMemoryLimitSetToINIInBytes); } }