2020-01-28 10:04:57 +00:00
< ? php
/**
2020-02-01 13:32:36 +00:00
* FuzeWorks Async Library
2020-01-28 10:04:57 +00:00
*
* The FuzeWorks PHP FrameWork
*
2020-02-01 13:32:36 +00:00
* Copyright ( C ) 2013 - 2020 TechFuze
2020-01-28 10:04:57 +00:00
*
* Permission is hereby granted , free of charge , to any person obtaining a copy
* of this software and associated documentation files ( the " Software " ), to deal
* in the Software without restriction , including without limitation the rights
* to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
* copies of the Software , and to permit persons to whom the Software is
* furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE .
*
* @ author TechFuze
2020-02-01 13:32:36 +00:00
* @ copyright Copyright ( c ) 2013 - 2020 , TechFuze . ( http :// techfuze . net )
2020-01-28 10:04:57 +00:00
* @ license https :// opensource . org / licenses / MIT MIT License
*
* @ link http :// techfuze . net / fuzeworks
2020-02-01 13:32:36 +00:00
* @ since Version 1.0 . 0
2020-01-28 10:04:57 +00:00
*
2020-02-01 13:32:36 +00:00
* @ version Version 1.0 . 0
2020-01-28 10:04:57 +00:00
*/
2020-02-01 13:32:36 +00:00
namespace FuzeWorks\Async\Executors ;
use FuzeWorks\Async\Executor ;
use FuzeWorks\Async\Process ;
use FuzeWorks\Async\Task ;
use FuzeWorks\Async\TasksException ;
2020-01-28 10:04:57 +00:00
class ShellExecutor implements Executor
{
private $binary ;
private $worker ;
2020-02-14 14:31:09 +00:00
private $bootstrapFile ;
2020-01-28 10:04:57 +00:00
private $stdout = " > /dev/null " ;
private $stderr = " 2> /dev/null " ;
/**
* ShellExecutor constructor .
*
2020-02-14 14:31:09 +00:00
* @ param string $bootstrapFile
* @ param array $parameters
2020-01-28 10:04:57 +00:00
* @ throws TasksException
*/
2020-02-14 14:31:09 +00:00
public function __construct ( string $bootstrapFile , array $parameters )
2020-01-28 10:04:57 +00:00
{
2020-02-14 14:31:09 +00:00
// Fetch workerFile
$workerFile = $parameters [ 'workerFile' ];
2020-01-28 10:04:57 +00:00
// First determine the PHP binary
$this -> binary = PHP_BINDIR . DS . 'php' ;
2020-02-14 14:31:09 +00:00
$this -> bootstrapFile = $bootstrapFile ;
2020-01-28 10:04:57 +00:00
if ( ! file_exists ( $workerFile ))
2020-02-14 14:31:09 +00:00
throw new TasksException ( " Could not construct ShellExecutor. ShellWorker script does not exist. " );
2020-01-28 10:04:57 +00:00
$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
2020-02-14 14:31:09 +00:00
$commandString = " $this->binary $this->worker --bootstrap= " . $this -> bootstrapFile . " -t %s " . ( $post ? 'p' : '' ) . " $this->stdout $this->stderr & echo $ ! " ;
2020-01-28 10:04:57 +00:00
// Then execute the command using the base64_encoded string of the taskID
$output = $this -> shellExec ( $commandString , [ base64_encode ( $task -> getId ())]);
2020-02-01 13:32:36 +00:00
$pid = intval ( $output [ 0 ]);
$task -> setProcess ( new Process ( $pid ));
2020-01-28 10:04:57 +00:00
// 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 " ;
2020-02-01 13:32:36 +00:00
// 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 ();
2020-01-28 10:04:57 +00:00
2020-02-01 13:32:36 +00:00
// And we execute the commandString to fetch info on the process
$output = $this -> shellExec ( $commandString , [ $pid ]);
2020-01-28 10:04:57 +00:00
2020-02-01 13:32:36 +00:00
// 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 ;
2020-01-28 10:04:57 +00:00
2020-02-01 13:32:36 +00:00
// Split up the info
$parts = preg_split ( " / \ s+/ " , trim ( $last ));
2020-01-28 10:04:57 +00:00
2020-02-01 13:32:36 +00:00
// 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' )
2020-01-28 10:04:57 +00:00
return null ;
2020-02-01 13:32:36 +00:00
// Finally, return the Task information
return $parts ;
2020-01-28 10:04:57 +00:00
}
public function getTaskExitCode ( Task $task ) : int
{
// TODO: Implement getTaskExitCode() method.
}
public function getRunningTasks () : array
{
// TODO: Implement getRunningTasks() method.
}
}