/dev/null"; private $stderr = "2> /dev/null"; /** * ShellExecutor constructor. * * @param string $bootstrapFile * @param array $parameters * @throws TasksException */ public function __construct(string $bootstrapFile, array $parameters) { // Fetch workerFile $workerFile = $parameters['workerFile']; // First determine the PHP binary $this->binary = PHP_BINDIR . DS . 'php'; $this->bootstrapFile = $bootstrapFile; if (!file_exists($workerFile)) throw new TasksException("Could not construct ShellExecutor. ShellWorker script does not exist."); $this->worker = $workerFile; } private function shellExec($format, array $parameters = []) { $parameters = array_map("escapeshellarg", $parameters); array_unshift($parameters, $format); $command = call_user_func_array("sprintf", $parameters); exec($command, $output); return $output; } public function startTask(Task $task, bool $post = false): Task { // First prepare the command used to spawn workers $commandString = "$this->binary $this->worker --bootstrap=".$this->bootstrapFile." -t %s ".($post ? 'p' : '')." $this->stdout $this->stderr & echo $!"; // Then execute the command using the base64_encoded string of the taskID $output = $this->shellExec($commandString, [base64_encode($task->getId())]); $pid = intval($output[0]); $task->setProcess(new Process($pid)); // And finally return the task return $task; } public function stopTask(Task $task): Task { // TODO: Implement stopTask() method. } public function getTaskRunning(Task $task): bool { $stats = $this->getTaskStats($task); return !is_null($stats); } public function getTaskStats(Task $task): ?array { // First prepare the command used to gather info on processes $commandString = "ps -o pid,%%cpu,%%mem,state,start -p %s | sed 1d"; // First we must determine what process is used. $process = $task->getProcess(); if (is_null($process)) return null; // Then using that process we determine the ProcessID $pid = $process->getPid(); // And we execute the commandString to fetch info on the process $output = $this->shellExec($commandString, [$pid]); // If not output is provided, the command failed and should return null if (count($output) < 1) return null; // ?? $last = $output[count($output) - 1]; if (trim($last) === "") return null; // Split up the info $parts = preg_split("/\s+/", trim($last)); // Determine the state of the process // If the process is in a 'zombie' state, it should be considered fully executed. // Cleanup of Zombie processes must take place by periodically restarting the SuperVisor, or by using a SuperVisor which does not have the zombie problem $state = strtoupper(trim($parts[3])); if ("{$pid}" !== $parts[0] || $state === 'Z') return null; // Finally, return the Task information return $parts; } public function getTaskExitCode(Task $task): int { // TODO: Implement getTaskExitCode() method. } public function getRunningTasks(): array { // TODO: Implement getRunningTasks() method. } }