FRED™  3.0
FRED™: Framework for Rapid and Easy Development
Parallel.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Rsi\Fred;
4 
5 /**
6  * Component for parallel execution.
7  */
8 class Parallel extends Component{
9 
10  public $timeout = 600; //!< Time after which the results may be removed by the garbage collector (seconds).
11  public $garbageChance = 10000; //!< Run garbage collector once every ... times a call is not ready.
12  public $lastError = [];
13 
14  protected $_path = null; //!< Path for storing the result files.
15  protected $_ext = '.dat';
16  protected $_initCode = null; //!< Initialization code (PHP).
17  protected $_fredVar = '$fred'; //!< Name for the variable that holds the \\Rsi\\Fred object after initalization.
18 
19  protected function filename($id){
20  if(!$this->_path) throw new \Exception('No path set');
21  if(!is_scalar($id) || !preg_match('/^\\w+$/',$id)) throw new \Exception('Invalid ID');
22  return $this->_path . $id . $this->_ext;
23  }
24 
25  protected function writeResult($id,$result = null){
26  file_put_contents($this->filename($id),func_num_args() > 1 ? serialize($result) : null);
27  }
28 
29  protected function readResult($id){
30  $result = unserialize(file_get_contents($filename = $this->filename($id)));
31  \Rsi\File::unlink($filename);
32  return $result;
33  }
34 
35  public function worker($id,$component_name,$func_name,$params = null){
36  $result = [];
37  if(is_string($component_name) && is_string($func_name)) try{
38  $result['result'] = call_user_func_array([$this->component($component_name),$func_name],is_array($params) ? $params : []);
39  }
40  catch(\Exception $e){
41  $result += [
42  'error' => $e->getMessage(),
43  'filename' => $e->getFile(),
44  'lineNo' => $e->getLine(),
45  'trace' => $e->getTrace()
46  ];
47  }
48  $this->writeResult($id,$result);
49  $this->_fred->halt();
50  }
51  /**
52  * Execute a command in the background.
53  * @param string $component_name Component to run the command on.
54  * @param string $func_name Function to call.
55  * @param array $params Parameters for the call.
56  * @return string Reference ID for the call (false on error).
57  */
58  public function execute($component_name,$func_name,$params = null){
59  if(!is_string($component_name) || !is_string($func_name)) return false;
60  $this->writeResult($id = \Rsi\Str::random());
61  \Rsi::executeParallel(escapeshellarg(PHP_BINARY) . ' -r ' . escapeshellarg(
62  $this->_initCode .
63  $this->_fredVar . '->component(' . var_export($this->_name,true) . ')->worker(' .
64  var_export($id,true) . ',' . var_export($component_name,true) . ',' . var_export($func_name,true) .
65  (is_array($params) ? ',' . var_export(array_values($params),true) : '') .
66  ');'
67  ));
68  return $id;
69  }
70 
71  protected function garbage(){
72  $time = time() - $this->timeout;
73  if($this->_path) foreach((new \GlobIterator($this->_path . '*' . $this->_ext)) as $filename => $file) try{
74  if($file->getMTime() < $time) unlink($filename);
75  }
76  catch(\Exception $e){
77  $this->component('log')->info($e);
78  error_clear_last();
79  }
80  }
81  /**
82  * Check if the calls are ready.
83  * @param string $ids Reference ID's for the calls.
84  * @return bool True if all calls are ready.
85  */
86  public function ready(...$ids){
87  foreach($ids as $id){
88  clearstatcache(false,$filename = $this->filename($id));
89  if(!filesize($filename)){
90  if(!rand(0,$this->garbageChance)) $this->garbage();
91  return false;
92  }
93  }
94  return true;
95  }
96  /**
97  * Get the result from the parallel call.
98  * @param string $id Reference ID for the call.
99  * @return mixed
100  */
101  public function result($id){
102  if(array_key_exists('result',$result = $this->readResult($id))) return $result['result'];
103  $this->lastError = $result;
104  throw new \Exception($result['error'] ?? 'Empty result');
105  }
106 
107  protected function getAvailable(){
108  return $this->_path && $this->_initCode;
109  }
110 
111 }
Rsi\Fred\Parallel\garbage
garbage()
Definition: Parallel.php:71
Rsi\Fred\Parallel\worker
worker($id, $component_name, $func_name, $params=null)
Definition: Parallel.php:35
Rsi
Rsi\Fred\Parallel\$timeout
$timeout
Time after which the results may be removed by the garbage collector (seconds).
Definition: Parallel.php:10
Rsi\Fred\Parallel
Component for parallel execution.
Definition: Parallel.php:8
Rsi\Fred\Parallel\filename
filename($id)
Definition: Parallel.php:19
Rsi\Fred\Parallel\writeResult
writeResult($id, $result=null)
Definition: Parallel.php:25
Rsi\Fred\Parallel\$lastError
$lastError
Definition: Parallel.php:12
Rsi\Fred\Parallel\$_ext
$_ext
Definition: Parallel.php:15
Rsi\Fred\Component
Basic component class.
Definition: Component.php:8
Rsi\Fred\Component\component
component($name)
Get a component (local or default).
Definition: Component.php:81
Rsi\Fred\Parallel\$garbageChance
$garbageChance
Run garbage collector once every ... times a call is not ready.
Definition: Parallel.php:11
Rsi\Fred\Parallel\result
result($id)
Get the result from the parallel call.
Definition: Parallel.php:101
Rsi\Fred\Parallel\$_initCode
$_initCode
Initialization code (PHP).
Definition: Parallel.php:16
Rsi\Fred\Parallel\getAvailable
getAvailable()
Definition: Parallel.php:107
Rsi\Fred\Parallel\readResult
readResult($id)
Definition: Parallel.php:29
Rsi\Fred\Parallel\execute
execute($component_name, $func_name, $params=null)
Execute a command in the background.
Definition: Parallel.php:58
Rsi\Fred\Parallel\$_fredVar
$_fredVar
Name for the variable that holds the \Rsi\Fred object after initalization.
Definition: Parallel.php:17
Rsi\Fred\Parallel\ready
ready(... $ids)
Check if the calls are ready.
Definition: Parallel.php:86
Rsi\Fred\Exception
Definition: Exception.php:5
Rsi\Fred
Definition: Alive.php:3
Rsi\Fred\Parallel\$_path
$_path
Path for storing the result files.
Definition: Parallel.php:14