Browse Source

Create Core\Process as a base for followup work

pull/7521/head
Philipp Holzer 1 month ago
parent
commit
2c73377b39
No account linked to committer's email address
4 changed files with 227 additions and 145 deletions
  1. 15
    144
      src/App.php
  2. 203
    0
      src/Core/Process.php
  3. 4
    1
      src/Core/Worker.php
  4. 5
    0
      static/dependencies.config.php

+ 15
- 144
src/App.php View File

@@ -127,6 +127,11 @@ class App
127 127
 	 */
128 128
 	private $args;
129 129
 
130
+	/**
131
+	 * @var Core\Process The process methods
132
+	 */
133
+	private $process;
134
+
130 135
 	/**
131 136
 	 * Returns the current config cache of this node
132 137
 	 *
@@ -225,8 +230,9 @@ class App
225 230
 	 * @param Profiler        $profiler     The profiler of this application
226 231
 	 * @param L10n            $l10n         The translator instance
227 232
 	 * @param App\Arguments   $args         The Friendica Arguments of the call
233
+	 * @param Core\Process $process The process methods
228 234
 	 */
229
-	public function __construct(Database $database, Configuration $config, App\Mode $mode, BaseURL $baseURL, LoggerInterface $logger, Profiler $profiler, L10n $l10n, Arguments $args, App\Module $module, App\Page $page)
235
+	public function __construct(Database $database, Configuration $config, App\Mode $mode, BaseURL $baseURL, LoggerInterface $logger, Profiler $profiler, L10n $l10n, Arguments $args, App\Module $module, App\Page $page, Core\Process $process)
230 236
 	{
231 237
 		$this->database     = $database;
232 238
 		$this->config       = $config;
@@ -236,6 +242,7 @@ class App
236 242
 		$this->logger       = $logger;
237 243
 		$this->l10n         = $l10n;
238 244
 		$this->args         = $args;
245
+		$this->process = $process;
239 246
 
240 247
 		$this->cmd          = $args->getCommand();
241 248
 		$this->argv         = $args->getArgv();
@@ -398,163 +405,27 @@ class App
398 405
 	}
399 406
 
400 407
 	/**
401
-	 * @brief Checks if the maximum number of database processes is reached
402
-	 *
403
-	 * @return bool Is the limit reached?
408
+	 * @deprecated 2019.09 - use Core\Process->isMaxProcessesReached() instead
404 409
 	 */
405 410
 	public function isMaxProcessesReached()
406 411
 	{
407
-		// Deactivated, needs more investigating if this check really makes sense
408
-		return false;
409
-
410
-		/*
411
-		 * Commented out to suppress static analyzer issues
412
-		 *
413
-		if ($this->is_backend()) {
414
-			$process = 'backend';
415
-			$max_processes = $this->config->get('system', 'max_processes_backend');
416
-			if (intval($max_processes) == 0) {
417
-				$max_processes = 5;
418
-			}
419
-		} else {
420
-			$process = 'frontend';
421
-			$max_processes = $this->config->get('system', 'max_processes_frontend');
422
-			if (intval($max_processes) == 0) {
423
-				$max_processes = 20;
424
-			}
425
-		}
426
-
427
-		$processlist = DBA::processlist();
428
-		if ($processlist['list'] != '') {
429
-			$this->logger->debug('Processcheck: Processes: ' . $processlist['amount'] . ' - Processlist: ' . $processlist['list']);
430
-
431
-			if ($processlist['amount'] > $max_processes) {
432
-				$this->logger->debug('Processcheck: Maximum number of processes for ' . $process . ' tasks (' . $max_processes . ') reached.');
433
-				return true;
434
-			}
435
-		}
436
-		return false;
437
-		 */
412
+		return $this->process->isMaxProcessesReached();
438 413
 	}
439 414
 
440 415
 	/**
441
-	 * @brief Checks if the minimal memory is reached
442
-	 *
443
-	 * @return bool Is the memory limit reached?
444
-	 * @throws HTTPException\InternalServerErrorException
416
+	 * @deprecated 2019.09 - use Core\Process->isMinMemoryReached() instead
445 417
 	 */
446 418
 	public function isMinMemoryReached()
447 419
 	{
448
-		$min_memory = $this->config->get('system', 'min_memory', 0);
449
-		if ($min_memory == 0) {
450
-			return false;
451
-		}
452
-
453
-		if (!is_readable('/proc/meminfo')) {
454
-			return false;
455
-		}
456
-
457
-		$memdata = explode("\n", file_get_contents('/proc/meminfo'));
458
-
459
-		$meminfo = [];
460
-		foreach ($memdata as $line) {
461
-			$data = explode(':', $line);
462
-			if (count($data) != 2) {
463
-				continue;
464
-			}
465
-			list($key, $val) = $data;
466
-			$meminfo[$key] = (int)trim(str_replace('kB', '', $val));
467
-			$meminfo[$key] = (int)($meminfo[$key] / 1024);
468
-		}
469
-
470
-		if (!isset($meminfo['MemFree'])) {
471
-			return false;
472
-		}
473
-
474
-		$free = $meminfo['MemFree'];
475
-
476
-		$reached = ($free < $min_memory);
477
-
478
-		if ($reached) {
479
-			$this->logger->debug('Minimal memory reached.', ['free' => $free, 'memtotal' => $meminfo['MemTotal'], 'limit' => $min_memory]);
480
-		}
481
-
482
-		return $reached;
420
+		return $this->process->isMinMemoryReached();
483 421
 	}
484 422
 
485 423
 	/**
486
-	 * @brief Checks if the maximum load is reached
487
-	 *
488
-	 * @return bool Is the load reached?
489
-	 * @throws HTTPException\InternalServerErrorException
424
+	 * @deprecated 2019.09 - use Core\Process->isMaxLoadReached() instead
490 425
 	 */
491 426
 	public function isMaxLoadReached()
492 427
 	{
493
-		if ($this->mode->isBackend()) {
494
-			$process    = 'backend';
495
-			$maxsysload = intval($this->config->get('system', 'maxloadavg'));
496
-			if ($maxsysload < 1) {
497
-				$maxsysload = 50;
498
-			}
499
-		} else {
500
-			$process    = 'frontend';
501
-			$maxsysload = intval($this->config->get('system', 'maxloadavg_frontend'));
502
-			if ($maxsysload < 1) {
503
-				$maxsysload = 50;
504
-			}
505
-		}
506
-
507
-		$load = Core\System::currentLoad();
508
-		if ($load) {
509
-			if (intval($load) > $maxsysload) {
510
-				$this->logger->info('system load for process too high.', ['load' => $load, 'process' => $process, 'maxsysload' => $maxsysload]);
511
-				return true;
512
-			}
513
-		}
514
-		return false;
515
-	}
516
-
517
-	/**
518
-	 * Executes a child process with 'proc_open'
519
-	 *
520
-	 * @param string $command The command to execute
521
-	 * @param array  $args    Arguments to pass to the command ( [ 'key' => value, 'key2' => value2, ... ]
522
-	 *
523
-	 * @throws HTTPException\InternalServerErrorException
524
-	 */
525
-	public function proc_run($command, $args)
526
-	{
527
-		if (!function_exists('proc_open')) {
528
-			return;
529
-		}
530
-
531
-		$cmdline = $this->config->get('config', 'php_path', 'php') . ' ' . escapeshellarg($command);
532
-
533
-		foreach ($args as $key => $value) {
534
-			if (!is_null($value) && is_bool($value) && !$value) {
535
-				continue;
536
-			}
537
-
538
-			$cmdline .= ' --' . $key;
539
-			if (!is_null($value) && !is_bool($value)) {
540
-				$cmdline .= ' ' . $value;
541
-			}
542
-		}
543
-
544
-		if ($this->isMinMemoryReached()) {
545
-			return;
546
-		}
547
-
548
-		if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
549
-			$resource = proc_open('cmd /c start /b ' . $cmdline, [], $foo, $this->getBasePath());
550
-		} else {
551
-			$resource = proc_open($cmdline . ' &', [], $foo, $this->getBasePath());
552
-		}
553
-		if (!is_resource($resource)) {
554
-			$this->logger->debug('We got no resource for command.', ['cmd' => $cmdline]);
555
-			return;
556
-		}
557
-		proc_close($resource);
428
+		return $this->process->isMaxLoadReached();
558 429
 	}
559 430
 
560 431
 	/**
@@ -729,7 +600,7 @@ class App
729 600
 			}
730 601
 
731 602
 			// Max Load Average reached: ERROR
732
-			if ($this->isMaxProcessesReached() || $this->isMaxLoadReached()) {
603
+			if ($this->process->isMaxProcessesReached() || $this->process->isMaxLoadReached()) {
733 604
 				header('Retry-After: 120');
734 605
 				header('Refresh: 120; url=' . $this->baseURL->get() . "/" . $this->args->getQueryString());
735 606
 

+ 203
- 0
src/Core/Process.php View File

@@ -0,0 +1,203 @@
1
+<?php
2
+
3
+namespace Friendica\Core;
4
+
5
+use Friendica\App;
6
+use Friendica\Core\Config\Configuration;
7
+use Psr\Log\LoggerInterface;
8
+
9
+/**
10
+ * Methods for interacting with the current process or create new process
11
+ *
12
+ * @todo 2019.12 Next release, this class holds all process relevant methods based on the big Worker class
13
+ *       - Starting new processes (including checks)
14
+ *       - Enabling multi-node processing (e.g. for docker service)
15
+ *         - Using an process-id per node
16
+ *         - Using memory locks for multi-node locking (redis, memcached, ..)
17
+ */
18
+final class Process
19
+{
20
+	/**
21
+	 * @var LoggerInterface
22
+	 */
23
+	private $logger;
24
+
25
+	/**
26
+	 * @var App\Mode
27
+	 */
28
+	private $mode;
29
+
30
+	/**
31
+	 * @var Configuration
32
+	 */
33
+	private $config;
34
+
35
+	/**
36
+	 * @var string
37
+	 */
38
+	private $basePath;
39
+
40
+	public function __construct(LoggerInterface $logger, App\Mode $mode, Configuration $config, string $basepath)
41
+	{
42
+		$this->logger   = $logger;
43
+		$this->mode     = $mode;
44
+		$this->config   = $config;
45
+		$this->basePath = $basepath;
46
+	}
47
+
48
+	/**
49
+	 * @brief Checks if the maximum number of database processes is reached
50
+	 *
51
+	 * @return bool Is the limit reached?
52
+	 */
53
+	public function isMaxProcessesReached()
54
+	{
55
+		// Deactivated, needs more investigating if this check really makes sense
56
+		return false;
57
+
58
+		/*
59
+		 * Commented out to suppress static analyzer issues
60
+		 *
61
+		if ($this->mode->isBackend()) {
62
+			$process = 'backend';
63
+			$max_processes = $this->config->get('system', 'max_processes_backend');
64
+			if (intval($max_processes) == 0) {
65
+				$max_processes = 5;
66
+			}
67
+		} else {
68
+			$process = 'frontend';
69
+			$max_processes = $this->config->get('system', 'max_processes_frontend');
70
+			if (intval($max_processes) == 0) {
71
+				$max_processes = 20;
72
+			}
73
+		}
74
+
75
+		$processlist = DBA::processlist();
76
+		if ($processlist['list'] != '') {
77
+			$this->logger->debug('Processcheck: Processes: ' . $processlist['amount'] . ' - Processlist: ' . $processlist['list']);
78
+
79
+			if ($processlist['amount'] > $max_processes) {
80
+				$this->logger->debug('Processcheck: Maximum number of processes for ' . $process . ' tasks (' . $max_processes . ') reached.');
81
+				return true;
82
+			}
83
+		}
84
+		return false;
85
+		 */
86
+	}
87
+
88
+	/**
89
+	 * @brief Checks if the minimal memory is reached
90
+	 *
91
+	 * @return bool Is the memory limit reached?
92
+	 */
93
+	public function isMinMemoryReached()
94
+	{
95
+		$min_memory = $this->config->get('system', 'min_memory', 0);
96
+		if ($min_memory == 0) {
97
+			return false;
98
+		}
99
+
100
+		if (!is_readable('/proc/meminfo')) {
101
+			return false;
102
+		}
103
+
104
+		$memdata = explode("\n", file_get_contents('/proc/meminfo'));
105
+
106
+		$meminfo = [];
107
+		foreach ($memdata as $line) {
108
+			$data = explode(':', $line);
109
+			if (count($data) != 2) {
110
+				continue;
111
+			}
112
+			list($key, $val) = $data;
113
+			$meminfo[$key] = (int)trim(str_replace('kB', '', $val));
114
+			$meminfo[$key] = (int)($meminfo[$key] / 1024);
115
+		}
116
+
117
+		if (!isset($meminfo['MemFree'])) {
118
+			return false;
119
+		}
120
+
121
+		$free = $meminfo['MemFree'];
122
+
123
+		$reached = ($free < $min_memory);
124
+
125
+		if ($reached) {
126
+			$this->logger->debug('Minimal memory reached.', ['free' => $free, 'memtotal' => $meminfo['MemTotal'], 'limit' => $min_memory]);
127
+		}
128
+
129
+		return $reached;
130
+	}
131
+
132
+	/**
133
+	 * @brief Checks if the maximum load is reached
134
+	 *
135
+	 * @return bool Is the load reached?
136
+	 */
137
+	public function isMaxLoadReached()
138
+	{
139
+		if ($this->mode->isBackend()) {
140
+			$process    = 'backend';
141
+			$maxsysload = intval($this->config->get('system', 'maxloadavg'));
142
+			if ($maxsysload < 1) {
143
+				$maxsysload = 50;
144
+			}
145
+		} else {
146
+			$process    = 'frontend';
147
+			$maxsysload = intval($this->config->get('system', 'maxloadavg_frontend'));
148
+			if ($maxsysload < 1) {
149
+				$maxsysload = 50;
150
+			}
151
+		}
152
+
153
+		$load = System::currentLoad();
154
+		if ($load) {
155
+			if (intval($load) > $maxsysload) {
156
+				$this->logger->info('system load for process too high.', ['load' => $load, 'process' => $process, 'maxsysload' => $maxsysload]);
157
+				return true;
158
+			}
159
+		}
160
+		return false;
161
+	}
162
+
163
+	/**
164
+	 * Executes a child process with 'proc_open'
165
+	 *
166
+	 * @param string $command The command to execute
167
+	 * @param array  $args    Arguments to pass to the command ( [ 'key' => value, 'key2' => value2, ... ]
168
+	 */
169
+	public function run($command, $args)
170
+	{
171
+		if (!function_exists('proc_open')) {
172
+			return;
173
+		}
174
+
175
+		$cmdline = $this->config->get('config', 'php_path', 'php') . ' ' . escapeshellarg($command);
176
+
177
+		foreach ($args as $key => $value) {
178
+			if (!is_null($value) && is_bool($value) && !$value) {
179
+				continue;
180
+			}
181
+
182
+			$cmdline .= ' --' . $key;
183
+			if (!is_null($value) && !is_bool($value)) {
184
+				$cmdline .= ' ' . $value;
185
+			}
186
+		}
187
+
188
+		if ($this->isMinMemoryReached()) {
189
+			return;
190
+		}
191
+
192
+		if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
193
+			$resource = proc_open('cmd /c start /b ' . $cmdline, [], $foo, $this->basePath);
194
+		} else {
195
+			$resource = proc_open($cmdline . ' &', [], $foo, $this->basePath);
196
+		}
197
+		if (!is_resource($resource)) {
198
+			$this->logger->debug('We got no resource for command.', ['cmd' => $cmdline]);
199
+			return;
200
+		}
201
+		proc_close($resource);
202
+	}
203
+}

+ 4
- 1
src/Core/Worker.php View File

@@ -5,6 +5,7 @@
5 5
 namespace Friendica\Core;
6 6
 
7 7
 use Friendica\BaseObject;
8
+use Friendica\Core;
8 9
 use Friendica\Database\DBA;
9 10
 use Friendica\Model\Process;
10 11
 use Friendica\Util\DateTimeFormat;
@@ -1082,7 +1083,9 @@ class Worker
1082 1083
 
1083 1084
 		$args = ['no_cron' => !$do_cron];
1084 1085
 
1085
-		get_app()->proc_run($command, $args);
1086
+		$a = get_app();
1087
+		$process = new Core\Process($a->getLogger(), $a->getMode(), $a->getConfig(), $a->getBasePath());
1088
+		$process->run($command, $args);
1086 1089
 
1087 1090
 		// after spawning we have to remove the flag.
1088 1091
 		if (Config::get('system', 'worker_daemon_mode', false)) {

+ 5
- 0
static/dependencies.config.php View File

@@ -154,4 +154,9 @@ return [
154 154
 			['determineModule', [], Dice::CHAIN_CALL],
155 155
 		],
156 156
 	],
157
+	Friendica\Core\Process::class => [
158
+		'constructParams' => [
159
+			[Dice::INSTANCE => '$basepath'],
160
+		],
161
+	],
157 162
 ];

Loading…
Cancel
Save