This commit is contained in:
Julio Cesar Laura Avendaño
2019-04-04 14:44:33 -04:00
parent 90a7b778a1
commit 0da9afd8d3
6 changed files with 350 additions and 3 deletions

View File

@@ -0,0 +1,98 @@
<?php
namespace ProcessMaker\Core;
/**
* Class to manage the processes that runs in the shell
*/
class ProcessesManager
{
// Class properties
private $processes;
private $sleepTime = 1;
private $terminated = [];
private $errors = [];
/**
* Class constructor
*
* @param array $processes
*/
public function __construct(array $processes)
{
$this->processes = $processes;
}
/**
* Get the list of terminated processes
*
* @return array
*/
public function getTerminated()
{
return $this->terminated;
}
/**
* Get the list of processes with errors
*
* @return array
*/
public function getErrors()
{
return $this->errors;
}
/**
* Set the sleep time after each statuses revision
*
* @param int $sleepTime
*/
public function setSleepTime($sleepTime)
{
$this->sleepTime = $sleepTime;
}
/**
* Run the processes
*/
public function run()
{
// Start all processes
foreach ($this->processes as $process) {
$process->run();
}
// Manage the processes
$this->manage();
}
/**
* Manage all started processes
*/
private function manage()
{
do {
// Check all remaining processes
foreach ($this->processes as $index => $process) {
// If the process has finished, save the info and destroy it
if ($process->getStatus() === RunProcess::TERMINATED || $process->getStatus() === RunProcess::ERROR) {
$processInfo = ['command' => $process->getCommand(), 'rawAnswer' => $process->getRawAnswer()];
if ($process->getStatus() === RunProcess::TERMINATED) {
// Processes completed successfully
$this->terminated[] = $processInfo;
} else {
// Processes completed with errors
$this->errors[] = $processInfo;
}
// Destroy the process
unset($this->processes[$index]);
}
}
// Waiting...
sleep($this->sleepTime);
} while (!empty($this->processes));
}
}

View File

@@ -0,0 +1,146 @@
<?php
namespace ProcessMaker\Core;
/**
* This class run a command in shell and stores the pointer to him
*/
class RunProcess
{
// Class constants
const TERMINATED = 'terminated';
const RUNNING = 'running';
const NOT_RUNNING = 'not_running';
const ERROR = 'error';
// This constant can be overrides in the child class according to the command response, always should be have a value
const EXPECTED_ANSWER = '1';
// Class properties
private $resource;
private $command;
private $rawAnswer;
private $status;
private $exitCode;
private $pipes;
private $descriptors = [
['pipe', 'r'],
['pipe', 'w'],
['pipe', 'w']
];
/**
* Class constructor
*
* @param string $command
*/
public function __construct($command)
{
$this->command = $command;
}
/**
* Class destructor, the resource created should be closed
*/
public function __destruct()
{
if (is_resource($this->resource)) {
proc_close($this->resource);
}
}
/**
* Get the command
*
* @return string
*/
public function getCommand()
{
return $this->command;
}
/**
* Get the raw response
*
* @return string|null
*/
public function getRawAnswer()
{
return $this->rawAnswer;
}
/**
* Get the status
*
* @return string
*/
public function getStatus()
{
// If already exist a status return this value
if ($this->status !== null) {
return $this->status;
}
// If doesn't exists a resource the process is not running
if (!is_resource($this->resource)) {
return self::NOT_RUNNING;
}
// If the process is running return this value
if ($this->isRunning()) {
return self::RUNNING;
}
// If the process is not running, parse the response to determine the status
$this->rawAnswer = stream_get_contents($this->pipes[1]);
$this->status = $this->parseAnswer();
return $this->status;
}
/**
* Get the exit code
*
* @return string|null
*/
public function getExitCode()
{
return $this->exitCode;
}
/**
* Run the command
*/
public function run()
{
$this->resource = proc_open($this->command, $this->descriptors, $this->pipes);
}
/**
* Process is running?
*
* @return bool
*/
public function isRunning()
{
// Get the process status
$status = proc_get_status($this->resource);
// If process is not running get the exit code
if ($status['running'] === false) {
$this->exitCode = $status['exitcode'];
}
return $status['running'];
}
/**
* Process the raw response and compare with the expected answer in order to determine the status
*
* @return string
*/
public function parseAnswer()
{
return $this->rawAnswer === self::EXPECTED_ANSWER ? self::TERMINATED : self::ERROR;
}
}