Encourage use of boolean operators (&&, ||) over logical operators (and, or)
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php namespace Comodojo\Extender\Runner; |
|||||||||||
2 | ||||||||||||
3 | use \Exception; |
|||||||||||
4 | use \Comodojo\Extender\Checks; |
|||||||||||
5 | use \Comodojo\Extender\Queue; |
|||||||||||
6 | use \Monolog\Logger; |
|||||||||||
7 | use \Comodojo\Exception\TaskException; |
|||||||||||
8 | ||||||||||||
9 | /** |
|||||||||||
10 | * Jobs runner |
|||||||||||
11 | * |
|||||||||||
12 | * @package Comodojo extender |
|||||||||||
13 | * @author Marco Giovinazzi <[email protected]> |
|||||||||||
14 | * @license GPL-3.0+ |
|||||||||||
15 | * |
|||||||||||
16 | * LICENSE: |
|||||||||||
17 | * |
|||||||||||
18 | * This program is free software: you can redistribute it and/or modify |
|||||||||||
19 | * it under the terms of the GNU Affero General Public License as |
|||||||||||
20 | * published by the Free Software Foundation, either version 3 of the |
|||||||||||
21 | * License, or (at your option) any later version. |
|||||||||||
22 | * |
|||||||||||
23 | * This program is distributed in the hope that it will be useful, |
|||||||||||
24 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||||||||||
25 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||||||||||
26 | * GNU Affero General Public License for more details. |
|||||||||||
27 | * |
|||||||||||
28 | * You should have received a copy of the GNU Affero General Public License |
|||||||||||
29 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
|||||||||||
30 | */ |
|||||||||||
31 | ||||||||||||
32 | class JobsRunner { |
|||||||||||
33 | ||||||||||||
34 | /** |
|||||||||||
35 | * Jobs database (a simple array!). |
|||||||||||
36 | * |
|||||||||||
37 | * @var array |
|||||||||||
38 | */ |
|||||||||||
39 | private $jobs = array(); |
|||||||||||
40 | ||||||||||||
41 | /** |
|||||||||||
42 | * Logger instance |
|||||||||||
43 | * |
|||||||||||
44 | * @var \Monolog\Logger |
|||||||||||
45 | */ |
|||||||||||
46 | private $logger = null; |
|||||||||||
47 | ||||||||||||
48 | /** |
|||||||||||
49 | * Multithread switch |
|||||||||||
50 | * |
|||||||||||
51 | * @var bool |
|||||||||||
52 | */ |
|||||||||||
53 | private $multithread = false; |
|||||||||||
54 | ||||||||||||
55 | /** |
|||||||||||
56 | * Array of completed processes |
|||||||||||
57 | * |
|||||||||||
58 | * @var array |
|||||||||||
59 | */ |
|||||||||||
60 | private $completed_processes = array(); |
|||||||||||
61 | ||||||||||||
62 | /** |
|||||||||||
63 | * Array of running processes |
|||||||||||
64 | * |
|||||||||||
65 | * @var array |
|||||||||||
66 | */ |
|||||||||||
67 | private $running_processes = array(); |
|||||||||||
68 | ||||||||||||
69 | /** |
|||||||||||
70 | * Array of forked processes |
|||||||||||
71 | * |
|||||||||||
72 | * @var array |
|||||||||||
73 | */ |
|||||||||||
74 | private $forked_processes = array(); |
|||||||||||
75 | ||||||||||||
76 | /** |
|||||||||||
77 | * Amount of data (bits) to read from interprocess sockets |
|||||||||||
78 | * |
|||||||||||
79 | * @var int |
|||||||||||
80 | */ |
|||||||||||
81 | private $max_result_bytes_in_multithread = null; |
|||||||||||
82 | ||||||||||||
83 | /** |
|||||||||||
84 | * Maximum child runtime (after this interval parent process will start to kill) |
|||||||||||
85 | * |
|||||||||||
86 | * @var array |
|||||||||||
87 | */ |
|||||||||||
88 | private $max_childs_runtime = null; |
|||||||||||
89 | ||||||||||||
90 | /** |
|||||||||||
91 | * Array of ipc inter-processes sockets |
|||||||||||
92 | * |
|||||||||||
93 | * @var array |
|||||||||||
94 | */ |
|||||||||||
95 | private $ipc_array = array(); |
|||||||||||
96 | ||||||||||||
97 | /** |
|||||||||||
98 | * Number of processes waiting in the queue |
|||||||||||
99 | * |
|||||||||||
100 | * @var int |
|||||||||||
101 | */ |
|||||||||||
102 | private $queued_processes = 0; |
|||||||||||
103 | ||||||||||||
104 | /** |
|||||||||||
105 | * Array of chunks from current jobs |
|||||||||||
106 | * |
|||||||||||
107 | * It is used to divide jobs in groups and generate the queue |
|||||||||||
108 | * |
|||||||||||
109 | * @var array |
|||||||||||
110 | */ |
|||||||||||
111 | private $queued_chunks = array(); |
|||||||||||
112 | ||||||||||||
113 | /** |
|||||||||||
114 | * Time between SIGTERM and SIGKILL when child is killed |
|||||||||||
115 | * |
|||||||||||
116 | * Just to give it a chance |
|||||||||||
117 | * |
|||||||||||
118 | * @var int |
|||||||||||
119 | */ |
|||||||||||
120 | static private $lagger_timeout = 5; |
|||||||||||
121 | ||||||||||||
122 | /** |
|||||||||||
123 | * Runner constructor |
|||||||||||
124 | * |
|||||||||||
125 | * @param \Comodojo\Extender\Debug $logger Logger instance |
|||||||||||
126 | * @param bool $multithread Enable/disable multithread mode |
|||||||||||
127 | * @param int $max_result_bytes_in_multithread Max result bytes |
|||||||||||
128 | * @param int $max_childs_runtime Max child runtime |
|||||||||||
129 | */ |
|||||||||||
130 | 12 | final public function __construct(Logger $logger, $multithread, $max_result_bytes_in_multithread, $max_childs_runtime) { |
||||||||||
131 | ||||||||||||
132 | 12 | $this->logger = $logger; |
||||||||||
133 | ||||||||||||
134 | 12 | $this->multithread = $multithread; |
||||||||||
135 | ||||||||||||
136 | 12 | $this->max_result_bytes_in_multithread = $max_result_bytes_in_multithread; |
||||||||||
137 | ||||||||||||
138 | 12 | $this->max_childs_runtime = $max_childs_runtime; |
||||||||||
139 | ||||||||||||
140 | 12 | } |
||||||||||
141 | ||||||||||||
142 | /** |
|||||||||||
143 | * Add job to current queue |
|||||||||||
144 | * |
|||||||||||
145 | * @param \Comodojo\Extender\Job\Job $job An instance of \Comodojo\Extender\Job\Job |
|||||||||||
146 | * |
|||||||||||
147 | * @return string A job unique identifier |
|||||||||||
148 | */ |
|||||||||||
149 | final public function addJob(\Comodojo\Extender\Job\Job $job) { |
|||||||||||
150 | ||||||||||||
151 | $uid = self::getJobUid(); |
|||||||||||
152 | ||||||||||||
153 | try { |
|||||||||||
154 | ||||||||||||
155 | $class = $job->getClass(); |
|||||||||||
156 | ||||||||||||
157 | if ( class_exists($class) === false ) throw new Exception("Task cannot be loaded"); |
|||||||||||
158 | ||||||||||||
159 | $this->jobs[$uid] = array( |
|||||||||||
160 | "name" => $job->getName(), |
|||||||||||
161 | "id" => $job->getId(), |
|||||||||||
162 | "parameters"=> $job->getParameters(), |
|||||||||||
163 | "task" => $job->getTask(), |
|||||||||||
164 | "class" => $class |
|||||||||||
165 | ); |
|||||||||||
166 | ||||||||||||
167 | } catch (Exception $e) { |
|||||||||||
168 | ||||||||||||
169 | $this->logger->error('Error including job', array( |
|||||||||||
170 | "JOBUID"=> $uid, |
|||||||||||
171 | "ERROR" => $e->getMessage(), |
|||||||||||
172 | "ERRID" => $e->getCode() |
|||||||||||
173 | )); |
|||||||||||
174 | ||||||||||||
175 | return false; |
|||||||||||
176 | ||||||||||||
177 | } |
|||||||||||
178 | ||||||||||||
179 | return $uid; |
|||||||||||
180 | ||||||||||||
181 | } |
|||||||||||
182 | ||||||||||||
183 | /** |
|||||||||||
184 | * Free (reset) runner instance |
|||||||||||
185 | * |
|||||||||||
186 | */ |
|||||||||||
187 | final public function free() { |
|||||||||||
188 | ||||||||||||
189 | $this->jobs = array(); |
|||||||||||
190 | $this->completed_processes = array(); |
|||||||||||
191 | $this->running_processes = array(); |
|||||||||||
192 | $this->forked_processes = array(); |
|||||||||||
193 | $this->ipc_array = array(); |
|||||||||||
194 | ||||||||||||
195 | } |
|||||||||||
196 | ||||||||||||
197 | /** |
|||||||||||
198 | * Execute job(s) in current queue |
|||||||||||
199 | * |
|||||||||||
200 | * @return array An array of completed processes |
|||||||||||
201 | */ |
|||||||||||
202 | final public function run() { |
|||||||||||
203 | ||||||||||||
204 | // if jobs > concurrent jobs, create the queue |
|||||||||||
205 | ||||||||||||
206 | if ( $this->multithread AND defined("EXTENDER_MAX_CHILDS") AND sizeof($this->jobs) > EXTENDER_MAX_CHILDS AND EXTENDER_MAX_CHILDS != 0 ) { |
|||||||||||
0 ignored issues
–
show
|
||||||||||||
207 | ||||||||||||
208 | $this->queued_processes = sizeof($this->jobs); |
|||||||||||
209 | ||||||||||||
210 | // split jobs in chunks |
|||||||||||
211 | ||||||||||||
212 | $this->queued_chunks = array_chunk($this->jobs, EXTENDER_MAX_CHILDS, true); |
|||||||||||
213 | ||||||||||||
214 | // exec chunks, one at time |
|||||||||||
215 | ||||||||||||
216 | foreach ( $this->queued_chunks as $chunk ) { |
|||||||||||
217 | ||||||||||||
218 | $this->queued_processes = $this->queued_processes - sizeof($chunk); |
|||||||||||
219 | ||||||||||||
220 | Queue::dump(sizeof($chunk), $this->queued_processes); |
|||||||||||
221 | ||||||||||||
222 | $this->forker($chunk); |
|||||||||||
223 | ||||||||||||
224 | View Code Duplication | if ( $this->multithread ) $this->logger->info("Extender forked ".sizeof($this->forked_processes)." process(es) in the running queue", $this->forked_processes); |
||||||||||
225 | ||||||||||||
226 | $this->catcher(); |
|||||||||||
227 | ||||||||||||
228 | $this->forked_processes = array(); |
|||||||||||
229 | ||||||||||||
230 | } |
|||||||||||
231 | ||||||||||||
232 | } else { |
|||||||||||
233 | ||||||||||||
234 | Queue::dump(sizeof($this->jobs), 0); |
|||||||||||
235 | ||||||||||||
236 | $this->forker($this->jobs); |
|||||||||||
237 | ||||||||||||
238 | View Code Duplication | if ( $this->multithread ) $this->logger->info("Extender forked ".sizeof($this->forked_processes)." process(es) in the running queue", $this->forked_processes); |
||||||||||
239 | ||||||||||||
240 | $this->catcher(); |
|||||||||||
241 | ||||||||||||
242 | } |
|||||||||||
243 | ||||||||||||
244 | // Dump the end queue status |
|||||||||||
245 | ||||||||||||
246 | Queue::dump(sizeof($this->running_processes), $this->queued_processes); |
|||||||||||
247 | ||||||||||||
248 | return $this->completed_processes; |
|||||||||||
249 | ||||||||||||
250 | } |
|||||||||||
251 | ||||||||||||
252 | /** |
|||||||||||
253 | * Terminate all running processes |
|||||||||||
254 | * |
|||||||||||
255 | * @param int Parent process pid |
|||||||||||
256 | * @param integer $parent_pid |
|||||||||||
257 | */ |
|||||||||||
258 | final public function killAll($parent_pid) { |
|||||||||||
259 | ||||||||||||
260 | foreach ( $this->running_processes as $pid => $process ) { |
|||||||||||
261 | ||||||||||||
262 | // if ( $pid !== $parent_pid) posix_kill($pid, SIGTERM); |
|||||||||||
263 | if ( $pid !== $parent_pid ) self::kill($pid); |
|||||||||||
264 | ||||||||||||
265 | } |
|||||||||||
266 | ||||||||||||
267 | } |
|||||||||||
268 | ||||||||||||
269 | /** |
|||||||||||
270 | * Fork or exec some jobs |
|||||||||||
271 | * |
|||||||||||
272 | * @param array $jobs A subset of $this->jobs to process in a round |
|||||||||||
273 | */ |
|||||||||||
274 | private function forker($jobs) { |
|||||||||||
275 | ||||||||||||
276 | foreach ( $jobs as $jobUid => $job ) { |
|||||||||||
277 | ||||||||||||
278 | if ( $this->multithread AND sizeof($jobs) > 1 ) { |
|||||||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
Using logical operators such as
and instead of && is generally not recommended.
PHP has two types of connecting operators (logical operators, and boolean operators):
The difference between these is the order in which they are executed. In most cases,
you would want to use a boolean operator like Let’s take a look at a few examples: // Logical operators have lower precedence:
$f = false or true;
// is executed like this:
($f = false) or true;
// Boolean operators have higher precedence:
$f = false || true;
// is executed like this:
$f = (false || true);
Logical Operators are used for Control-FlowOne case where you explicitly want to use logical operators is for control-flow such as this: $x === 5
or die('$x must be 5.');
// Instead of
if ($x !== 5) {
die('$x must be 5.');
}
Since // The following is currently a parse error.
$x === 5
or throw new RuntimeException('$x must be 5.');
These limitations lead to logical operators rarely being of use in current PHP code. ![]() |
||||||||||||
279 | ||||||||||||
280 | $status = $this->runMultithread($jobUid); |
|||||||||||
281 | ||||||||||||
282 | if ( !is_null($status["pid"]) ) { |
|||||||||||
283 | ||||||||||||
284 | $this->running_processes[$status["pid"]] = array($status["name"], $status["uid"], $status["timestamp"], $status["id"]); |
|||||||||||
285 | ||||||||||||
286 | array_push($this->forked_processes, $status["pid"]); |
|||||||||||
287 | ||||||||||||
288 | } |
|||||||||||
289 | ||||||||||||
290 | } else { |
|||||||||||
291 | ||||||||||||
292 | $status = $this->runSinglethread($jobUid); |
|||||||||||
293 | ||||||||||||
294 | array_push($this->completed_processes, $status); |
|||||||||||
295 | ||||||||||||
296 | } |
|||||||||||
297 | ||||||||||||
298 | } |
|||||||||||
299 | ||||||||||||
300 | } |
|||||||||||
301 | ||||||||||||
302 | /** |
|||||||||||
303 | * Catch results from completed jobs |
|||||||||||
304 | * |
|||||||||||
305 | */ |
|||||||||||
306 | private function catcher() { |
|||||||||||
307 | ||||||||||||
308 | $exec_time = microtime(true); |
|||||||||||
309 | ||||||||||||
310 | while ( !empty($this->running_processes) ) { |
|||||||||||
311 | ||||||||||||
312 | foreach ( $this->running_processes as $pid => $job ) { |
|||||||||||
313 | ||||||||||||
314 | //$job[0] is name |
|||||||||||
315 | //$job[1] is uid |
|||||||||||
316 | //$job[2] is start timestamp |
|||||||||||
317 | //$job[3] is job id |
|||||||||||
318 | ||||||||||||
319 | if ( !self::isRunning($pid) ) { |
|||||||||||
320 | ||||||||||||
321 | list($reader, $writer) = $this->ipc_array[$job[1]]; |
|||||||||||
322 | ||||||||||||
323 | socket_close($writer); |
|||||||||||
324 | ||||||||||||
325 | $parent_result = socket_read($reader, $this->max_result_bytes_in_multithread, PHP_BINARY_READ); |
|||||||||||
326 | ||||||||||||
327 | if ( $parent_result === false ) { |
|||||||||||
328 | ||||||||||||
329 | $this->logger->error("socket_read() failed. Reason: ".socket_strerror(socket_last_error($reader))); |
|||||||||||
330 | ||||||||||||
331 | array_push($this->completed_processes, Array( |
|||||||||||
332 | null, |
|||||||||||
333 | $job[0], //$job_name, |
|||||||||||
334 | false, |
|||||||||||
335 | $job[2], //$start_timestamp, |
|||||||||||
336 | null, |
|||||||||||
337 | "socket_read() failed. Reason: ".socket_strerror(socket_last_error($reader)), |
|||||||||||
338 | $job[3], |
|||||||||||
339 | null |
|||||||||||
340 | )); |
|||||||||||
341 | ||||||||||||
342 | $status = 'ERROR'; |
|||||||||||
343 | ||||||||||||
344 | } else { |
|||||||||||
345 | ||||||||||||
346 | $result = unserialize(rtrim($parent_result)); |
|||||||||||
347 | ||||||||||||
348 | socket_close($reader); |
|||||||||||
349 | ||||||||||||
350 | array_push($this->completed_processes, Array( |
|||||||||||
351 | $pid, |
|||||||||||
352 | $job[0], //$job_name, |
|||||||||||
353 | $result["success"], |
|||||||||||
354 | $job[2], //$start_timestamp, |
|||||||||||
355 | $result["timestamp"], |
|||||||||||
356 | $result["result"], |
|||||||||||
357 | $job[3], |
|||||||||||
358 | $result["worklogid"] |
|||||||||||
359 | )); |
|||||||||||
360 | ||||||||||||
361 | $status = $result["success"] ? 'success' : 'failure'; |
|||||||||||
362 | ||||||||||||
363 | } |
|||||||||||
364 | ||||||||||||
365 | $this->logger->notice("Job ".$job[0]."(".$job[3].") ends with ".$status); |
|||||||||||
366 | ||||||||||||
367 | unset($this->running_processes[$pid]); |
|||||||||||
368 | ||||||||||||
369 | $this->logger->info("Removed pid ".$pid." from the running queue, job terminated with ".$status); |
|||||||||||
370 | ||||||||||||
371 | } else { |
|||||||||||
372 | ||||||||||||
373 | $current_time = microtime(true); |
|||||||||||
374 | ||||||||||||
375 | if ( $current_time > $exec_time + $this->max_childs_runtime ) { |
|||||||||||
376 | ||||||||||||
377 | $this->logger->warning("Killing pid ".$pid." due to maximum exec time reached (>".$this->max_childs_runtime.")", array( |
|||||||||||
378 | "START_TIME" => $exec_time, |
|||||||||||
379 | "CURRENT_TIME" => $current_time, |
|||||||||||
380 | "MAX_RUNTIME" => $this->max_childs_runtime |
|||||||||||
381 | )); |
|||||||||||
382 | ||||||||||||
383 | $kill = self::kill($pid); |
|||||||||||
384 | ||||||||||||
385 | if ( $kill ) $this->logger->warning("Pid ".$pid." killed"); |
|||||||||||
386 | ||||||||||||
387 | else $this->logger->warning("Pid ".$pid." could not be killed"); |
|||||||||||
388 | ||||||||||||
389 | list($reader, $writer) = $this->ipc_array[$job[1]]; |
|||||||||||
390 | ||||||||||||
391 | socket_close($writer); |
|||||||||||
392 | socket_close($reader); |
|||||||||||
393 | ||||||||||||
394 | array_push($this->completed_processes, Array( |
|||||||||||
395 | $pid, |
|||||||||||
396 | $job[0], //$job_name, |
|||||||||||
397 | false, |
|||||||||||
398 | $job[2], //$start_timestamp, |
|||||||||||
399 | $current_time, |
|||||||||||
400 | "Job ".$job[0]." killed due to maximum exec time reached (>".$this->max_childs_runtime.")", |
|||||||||||
401 | $job[3], |
|||||||||||
402 | null |
|||||||||||
403 | )); |
|||||||||||
404 | ||||||||||||
405 | $this->logger->notice("Job ".$job[0]."(".$job[3].") ends with error"); |
|||||||||||
406 | ||||||||||||
407 | unset($this->running_processes[$pid]); |
|||||||||||
408 | ||||||||||||
409 | $this->logger->info("Removed pid ".$pid." from the running queue, job terminated with error"); |
|||||||||||
410 | ||||||||||||
411 | } |
|||||||||||
412 | ||||||||||||
413 | } |
|||||||||||
414 | ||||||||||||
415 | } |
|||||||||||
416 | ||||||||||||
417 | } |
|||||||||||
418 | ||||||||||||
419 | } |
|||||||||||
420 | ||||||||||||
421 | /** |
|||||||||||
422 | * Run job in singlethread mode |
|||||||||||
423 | * |
|||||||||||
424 | * @param string Job unique identifier |
|||||||||||
425 | * |
|||||||||||
426 | * @return array {[pid],[name],[success],[start],[end],[result],[id]} |
|||||||||||
427 | */ |
|||||||||||
428 | private function runSinglethread($jobUid) { |
|||||||||||
429 | ||||||||||||
430 | $job = $this->jobs[$jobUid]; |
|||||||||||
431 | ||||||||||||
432 | // get job start timestamp |
|||||||||||
433 | $start_timestamp = microtime(true); |
|||||||||||
434 | ||||||||||||
435 | $this->logger->notice("Starting job ".$job['name']."(".$job['id'].")"); |
|||||||||||
436 | ||||||||||||
437 | $name = $job['name']; |
|||||||||||
438 | ||||||||||||
439 | $id = $job['id']; |
|||||||||||
440 | ||||||||||||
441 | $parameters = $job['parameters']; |
|||||||||||
442 | ||||||||||||
443 | $task = $job['task']; |
|||||||||||
444 | ||||||||||||
445 | $task_class = $job['class']; |
|||||||||||
446 | ||||||||||||
447 | try { |
|||||||||||
448 | ||||||||||||
449 | // create a task instance |
|||||||||||
450 | ||||||||||||
451 | $thetask = new $task_class($parameters, $this->logger, null, $name, $start_timestamp, false, $id); |
|||||||||||
452 | ||||||||||||
453 | // get the task pid (we are in singlethread mode) |
|||||||||||
454 | ||||||||||||
455 | $pid = $thetask->getPid(); |
|||||||||||
456 | ||||||||||||
457 | // run task |
|||||||||||
458 | ||||||||||||
459 | $result = $thetask->start(); |
|||||||||||
460 | ||||||||||||
461 | } catch (TaskException $te) { |
|||||||||||
462 | ||||||||||||
463 | $this->logger->notice("Job ".$job['name']."(".$job['id'].") ends with error"); |
|||||||||||
464 | ||||||||||||
465 | return array($pid, $name, false, $start_timestamp, $te->getEndTimestamp(), $te->getMessage(), $id, $te->getWorklogId()); |
|||||||||||
466 | ||||||||||||
467 | } catch (Exception $e) { |
|||||||||||
468 | ||||||||||||
469 | $this->logger->notice("Job ".$job['name']."(".$job['id'].") ends with error"); |
|||||||||||
470 | ||||||||||||
471 | return array($pid, $name, false, $start_timestamp, null, $e->getMessage(), $id, null); |
|||||||||||
472 | ||||||||||||
473 | } |
|||||||||||
474 | ||||||||||||
475 | $this->logger->notice("Job ".$job['name']."(".$job['id'].") ends with ".($result["success"] ? "success" : "failure")); |
|||||||||||
476 | ||||||||||||
477 | return array($pid, $name, $result["success"], $start_timestamp, $result["timestamp"], $result["result"], $id, $result["worklogid"]); |
|||||||||||
478 | ||||||||||||
479 | } |
|||||||||||
480 | ||||||||||||
481 | /** |
|||||||||||
482 | * Run job in singlethread mode |
|||||||||||
483 | * |
|||||||||||
484 | * @param string Job unique identifier |
|||||||||||
485 | * |
|||||||||||
486 | * @return array {[pid],[name],[success],[start],[end],[result],[id]} |
|||||||||||
487 | */ |
|||||||||||
488 | private function runMultithread($jobUid) { |
|||||||||||
489 | ||||||||||||
490 | $job = $this->jobs[$jobUid]; |
|||||||||||
491 | ||||||||||||
492 | // get job start timestamp |
|||||||||||
493 | $start_timestamp = microtime(true); |
|||||||||||
494 | ||||||||||||
495 | $this->logger->notice("Starting job ".$job['name']."(".$job['id'].")"); |
|||||||||||
496 | ||||||||||||
497 | $name = $job['name']; |
|||||||||||
498 | ||||||||||||
499 | $id = $job['id']; |
|||||||||||
500 | ||||||||||||
501 | $parameters = $job['parameters']; |
|||||||||||
502 | ||||||||||||
503 | $task = $job['task']; |
|||||||||||
504 | ||||||||||||
505 | $task_class = $job['class']; |
|||||||||||
506 | ||||||||||||
507 | $this->ipc_array[$jobUid] = array(); |
|||||||||||
508 | ||||||||||||
509 | // create a comm socket |
|||||||||||
510 | $socket = socket_create_pair(AF_UNIX, SOCK_STREAM, 0, $this->ipc_array[$jobUid]); |
|||||||||||
511 | ||||||||||||
512 | if ( $socket === false ) { |
|||||||||||
513 | ||||||||||||
514 | $this->logger->error("No IPC communication, aborting", array( |
|||||||||||
515 | "JOBUID"=> $jobUid, |
|||||||||||
516 | "ERROR" => socket_strerror(socket_last_error()), |
|||||||||||
517 | "ERRID" => null |
|||||||||||
518 | )); |
|||||||||||
519 | ||||||||||||
520 | array_push($this->completed_processes, array( |
|||||||||||
521 | null, |
|||||||||||
522 | $name, |
|||||||||||
523 | false, |
|||||||||||
524 | $start_timestamp, |
|||||||||||
525 | microtime(true), |
|||||||||||
526 | 'No IPC communication, exiting - '.socket_strerror(socket_last_error()), |
|||||||||||
527 | $id, |
|||||||||||
528 | null |
|||||||||||
529 | )); |
|||||||||||
530 | ||||||||||||
531 | return array( |
|||||||||||
532 | "pid" => null, |
|||||||||||
533 | "name" => $name, |
|||||||||||
534 | "uid" => $jobUid, |
|||||||||||
535 | "timestamp" => $start_timestamp, |
|||||||||||
536 | "id" => $id |
|||||||||||
537 | ); |
|||||||||||
538 | ||||||||||||
539 | } |
|||||||||||
540 | ||||||||||||
541 | list($reader, $writer) = $this->ipc_array[$jobUid]; |
|||||||||||
542 | ||||||||||||
543 | $pid = pcntl_fork(); |
|||||||||||
544 | ||||||||||||
545 | if ( $pid == -1 ) { |
|||||||||||
546 | ||||||||||||
547 | $this->logger->error("Could not fok job, aborting"); |
|||||||||||
548 | ||||||||||||
549 | array_push($this->completed_processes, Array( |
|||||||||||
550 | null, |
|||||||||||
551 | $name, |
|||||||||||
552 | false, |
|||||||||||
553 | $start_timestamp, |
|||||||||||
554 | microtime(true), |
|||||||||||
555 | 'Could not fok job', |
|||||||||||
556 | $id, |
|||||||||||
557 | null |
|||||||||||
558 | )); |
|||||||||||
559 | ||||||||||||
560 | } elseif ( $pid ) { |
|||||||||||
561 | ||||||||||||
562 | //PARENT will take actions on processes later |
|||||||||||
563 | ||||||||||||
564 | self::adjustNiceness($pid, $this->logger); |
|||||||||||
565 | ||||||||||||
566 | } else { |
|||||||||||
567 | ||||||||||||
568 | socket_close($reader); |
|||||||||||
569 | ||||||||||||
570 | $thetask = new $task_class($parameters, $this->logger, null, $name, $start_timestamp, true, $id); |
|||||||||||
571 | ||||||||||||
572 | try { |
|||||||||||
573 | ||||||||||||
574 | $result = $thetask->start(); |
|||||||||||
575 | ||||||||||||
576 | $return = serialize(array( |
|||||||||||
577 | "success" => $result["success"], |
|||||||||||
578 | "result" => $result["result"], |
|||||||||||
579 | "timestamp" => $result["timestamp"], |
|||||||||||
580 | "worklogid" => $result["worklogid"] |
|||||||||||
581 | )); |
|||||||||||
582 | ||||||||||||
583 | $exit = 0; |
|||||||||||
584 | ||||||||||||
585 | } catch (TaskException $te) { |
|||||||||||
586 | ||||||||||||
587 | $return = serialize(Array( |
|||||||||||
588 | "success" => false, |
|||||||||||
589 | "result" => $te->getMessage(), |
|||||||||||
590 | "timestamp" => $te->getEndTimestamp(), |
|||||||||||
591 | "worklogid" => $te->getWorklogId() |
|||||||||||
592 | )); |
|||||||||||
593 | ||||||||||||
594 | $exit = 1; |
|||||||||||
595 | ||||||||||||
596 | } catch (Exception $e) { |
|||||||||||
597 | ||||||||||||
598 | $return = serialize(Array( |
|||||||||||
599 | "success" => false, |
|||||||||||
600 | "result" => $e->getMessage(), |
|||||||||||
601 | "timestamp" => microtime(true), |
|||||||||||
602 | "worklogid" => null |
|||||||||||
603 | )); |
|||||||||||
604 | ||||||||||||
605 | $exit = 1; |
|||||||||||
606 | ||||||||||||
607 | } |
|||||||||||
608 | ||||||||||||
609 | if ( socket_write($writer, $return, strlen($return)) === false ) { |
|||||||||||
610 | ||||||||||||
611 | $this->logger->error("socket_write() failed ", array( |
|||||||||||
612 | "ERROR" => socket_strerror(socket_last_error($writer)) |
|||||||||||
613 | )); |
|||||||||||
614 | ||||||||||||
615 | } |
|||||||||||
616 | ||||||||||||
617 | socket_close($writer); |
|||||||||||
618 | ||||||||||||
619 | exit($exit); |
|||||||||||
620 | ||||||||||||
621 | } |
|||||||||||
622 | ||||||||||||
623 | return array( |
|||||||||||
624 | "pid" => $pid == -1 ? null : $pid, |
|||||||||||
625 | "name" => $name, |
|||||||||||
626 | "uid" => $jobUid, |
|||||||||||
627 | "id" => $id, |
|||||||||||
628 | "timestamp" => $start_timestamp |
|||||||||||
629 | ); |
|||||||||||
630 | ||||||||||||
631 | } |
|||||||||||
632 | ||||||||||||
633 | /** |
|||||||||||
634 | * Return true if process is still running, false otherwise |
|||||||||||
635 | * |
|||||||||||
636 | * @return bool |
|||||||||||
637 | */ |
|||||||||||
638 | private static function isRunning($pid) { |
|||||||||||
639 | ||||||||||||
640 | return (pcntl_waitpid($pid, $status, WNOHANG) === 0); |
|||||||||||
641 | ||||||||||||
642 | } |
|||||||||||
643 | ||||||||||||
644 | /** |
|||||||||||
645 | * Kill a child process |
|||||||||||
646 | * |
|||||||||||
647 | * @return bool |
|||||||||||
648 | */ |
|||||||||||
649 | private static function kill($pid) { |
|||||||||||
650 | ||||||||||||
651 | $kill_time = time() + self::$lagger_timeout; |
|||||||||||
652 | ||||||||||||
653 | $term = posix_kill($pid, SIGTERM); |
|||||||||||
654 | ||||||||||||
655 | while ( time() < $kill_time ) { |
|||||||||||
656 | ||||||||||||
657 | if ( !self::isRunning($pid) ) return $term; |
|||||||||||
658 | ||||||||||||
659 | } |
|||||||||||
660 | ||||||||||||
661 | return posix_kill($pid, SIGKILL); |
|||||||||||
662 | ||||||||||||
663 | } |
|||||||||||
664 | ||||||||||||
665 | /** |
|||||||||||
666 | * Get a job unique identifier |
|||||||||||
667 | * |
|||||||||||
668 | * @return string |
|||||||||||
669 | */ |
|||||||||||
670 | private static function getJobUid() { |
|||||||||||
671 | ||||||||||||
672 | return md5(uniqid(rand(), true), 0); |
|||||||||||
673 | ||||||||||||
674 | } |
|||||||||||
675 | ||||||||||||
676 | /** |
|||||||||||
677 | * Change child process priority according to EXTENDER_NICENESS |
|||||||||||
678 | * |
|||||||||||
679 | */ |
|||||||||||
680 | private static function adjustNiceness($pid, $logger) { |
|||||||||||
681 | ||||||||||||
682 | if ( Checks::multithread() AND defined("EXTENDER_CHILD_NICENESS") ) { |
|||||||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
Using logical operators such as
and instead of && is generally not recommended.
PHP has two types of connecting operators (logical operators, and boolean operators):
The difference between these is the order in which they are executed. In most cases,
you would want to use a boolean operator like Let’s take a look at a few examples: // Logical operators have lower precedence:
$f = false or true;
// is executed like this:
($f = false) or true;
// Boolean operators have higher precedence:
$f = false || true;
// is executed like this:
$f = (false || true);
Logical Operators are used for Control-FlowOne case where you explicitly want to use logical operators is for control-flow such as this: $x === 5
or die('$x must be 5.');
// Instead of
if ($x !== 5) {
die('$x must be 5.');
}
Since // The following is currently a parse error.
$x === 5
or throw new RuntimeException('$x must be 5.');
These limitations lead to logical operators rarely being of use in current PHP code. ![]() |
||||||||||||
683 | ||||||||||||
684 | $niceness = pcntl_setpriority($pid, EXTENDER_CHILD_NICENESS); |
|||||||||||
685 | ||||||||||||
686 | if ( $niceness == false ) $logger->warning("Unable to set child process ".$pid." niceness to ".EXTENDER_CHILD_NICENESS); |
|||||||||||
687 | ||||||||||||
688 | } |
|||||||||||
689 | ||||||||||||
690 | } |
|||||||||||
691 | ||||||||||||
692 | } |
|||||||||||
693 |
PHP has two types of connecting operators (logical operators, and boolean operators):
and
&&
or
||
The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like
&&
, or||
.Let’s take a look at a few examples:
Logical Operators are used for Control-Flow
One case where you explicitly want to use logical operators is for control-flow such as this:
Since
die
introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined withthrow
at this point:These limitations lead to logical operators rarely being of use in current PHP code.