diff --git a/src/App.php b/src/App.php index f417224e01..53011231ab 100644 --- a/src/App.php +++ b/src/App.php @@ -127,6 +127,11 @@ class App */ private $args; + /** + * @var Core\Process The process methods + */ + private $process; + /** * Returns the current config cache of this node * @@ -225,8 +230,9 @@ class App * @param Profiler $profiler The profiler of this application * @param L10n $l10n The translator instance * @param App\Arguments $args The Friendica Arguments of the call + * @param Core\Process $process The process methods */ - 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) + 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) { $this->database = $database; $this->config = $config; @@ -236,6 +242,7 @@ class App $this->logger = $logger; $this->l10n = $l10n; $this->args = $args; + $this->process = $process; $this->cmd = $args->getCommand(); $this->argv = $args->getArgv(); @@ -398,163 +405,27 @@ class App } /** - * @brief Checks if the maximum number of database processes is reached - * - * @return bool Is the limit reached? + * @deprecated 2019.09 - use Core\Process->isMaxProcessesReached() instead */ public function isMaxProcessesReached() { - // Deactivated, needs more investigating if this check really makes sense - return false; - - /* - * Commented out to suppress static analyzer issues - * - if ($this->is_backend()) { - $process = 'backend'; - $max_processes = $this->config->get('system', 'max_processes_backend'); - if (intval($max_processes) == 0) { - $max_processes = 5; - } - } else { - $process = 'frontend'; - $max_processes = $this->config->get('system', 'max_processes_frontend'); - if (intval($max_processes) == 0) { - $max_processes = 20; - } - } - - $processlist = DBA::processlist(); - if ($processlist['list'] != '') { - $this->logger->debug('Processcheck: Processes: ' . $processlist['amount'] . ' - Processlist: ' . $processlist['list']); - - if ($processlist['amount'] > $max_processes) { - $this->logger->debug('Processcheck: Maximum number of processes for ' . $process . ' tasks (' . $max_processes . ') reached.'); - return true; - } - } - return false; - */ + return $this->process->isMaxProcessesReached(); } /** - * @brief Checks if the minimal memory is reached - * - * @return bool Is the memory limit reached? - * @throws HTTPException\InternalServerErrorException + * @deprecated 2019.09 - use Core\Process->isMinMemoryReached() instead */ public function isMinMemoryReached() { - $min_memory = $this->config->get('system', 'min_memory', 0); - if ($min_memory == 0) { - return false; - } - - if (!is_readable('/proc/meminfo')) { - return false; - } - - $memdata = explode("\n", file_get_contents('/proc/meminfo')); - - $meminfo = []; - foreach ($memdata as $line) { - $data = explode(':', $line); - if (count($data) != 2) { - continue; - } - list($key, $val) = $data; - $meminfo[$key] = (int)trim(str_replace('kB', '', $val)); - $meminfo[$key] = (int)($meminfo[$key] / 1024); - } - - if (!isset($meminfo['MemFree'])) { - return false; - } - - $free = $meminfo['MemFree']; - - $reached = ($free < $min_memory); - - if ($reached) { - $this->logger->debug('Minimal memory reached.', ['free' => $free, 'memtotal' => $meminfo['MemTotal'], 'limit' => $min_memory]); - } - - return $reached; + return $this->process->isMinMemoryReached(); } /** - * @brief Checks if the maximum load is reached - * - * @return bool Is the load reached? - * @throws HTTPException\InternalServerErrorException + * @deprecated 2019.09 - use Core\Process->isMaxLoadReached() instead */ public function isMaxLoadReached() { - if ($this->mode->isBackend()) { - $process = 'backend'; - $maxsysload = intval($this->config->get('system', 'maxloadavg')); - if ($maxsysload < 1) { - $maxsysload = 50; - } - } else { - $process = 'frontend'; - $maxsysload = intval($this->config->get('system', 'maxloadavg_frontend')); - if ($maxsysload < 1) { - $maxsysload = 50; - } - } - - $load = Core\System::currentLoad(); - if ($load) { - if (intval($load) > $maxsysload) { - $this->logger->info('system load for process too high.', ['load' => $load, 'process' => $process, 'maxsysload' => $maxsysload]); - return true; - } - } - return false; - } - - /** - * Executes a child process with 'proc_open' - * - * @param string $command The command to execute - * @param array $args Arguments to pass to the command ( [ 'key' => value, 'key2' => value2, ... ] - * - * @throws HTTPException\InternalServerErrorException - */ - public function proc_run($command, $args) - { - if (!function_exists('proc_open')) { - return; - } - - $cmdline = $this->config->get('config', 'php_path', 'php') . ' ' . escapeshellarg($command); - - foreach ($args as $key => $value) { - if (!is_null($value) && is_bool($value) && !$value) { - continue; - } - - $cmdline .= ' --' . $key; - if (!is_null($value) && !is_bool($value)) { - $cmdline .= ' ' . $value; - } - } - - if ($this->isMinMemoryReached()) { - return; - } - - if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { - $resource = proc_open('cmd /c start /b ' . $cmdline, [], $foo, $this->getBasePath()); - } else { - $resource = proc_open($cmdline . ' &', [], $foo, $this->getBasePath()); - } - if (!is_resource($resource)) { - $this->logger->debug('We got no resource for command.', ['cmd' => $cmdline]); - return; - } - proc_close($resource); + return $this->process->isMaxLoadReached(); } /** @@ -729,7 +600,7 @@ class App } // Max Load Average reached: ERROR - if ($this->isMaxProcessesReached() || $this->isMaxLoadReached()) { + if ($this->process->isMaxProcessesReached() || $this->process->isMaxLoadReached()) { header('Retry-After: 120'); header('Refresh: 120; url=' . $this->baseURL->get() . "/" . $this->args->getQueryString()); diff --git a/src/Core/Process.php b/src/Core/Process.php new file mode 100644 index 0000000000..035f4bf0af --- /dev/null +++ b/src/Core/Process.php @@ -0,0 +1,203 @@ +logger = $logger; + $this->mode = $mode; + $this->config = $config; + $this->basePath = $basepath; + } + + /** + * @brief Checks if the maximum number of database processes is reached + * + * @return bool Is the limit reached? + */ + public function isMaxProcessesReached() + { + // Deactivated, needs more investigating if this check really makes sense + return false; + + /* + * Commented out to suppress static analyzer issues + * + if ($this->mode->isBackend()) { + $process = 'backend'; + $max_processes = $this->config->get('system', 'max_processes_backend'); + if (intval($max_processes) == 0) { + $max_processes = 5; + } + } else { + $process = 'frontend'; + $max_processes = $this->config->get('system', 'max_processes_frontend'); + if (intval($max_processes) == 0) { + $max_processes = 20; + } + } + + $processlist = DBA::processlist(); + if ($processlist['list'] != '') { + $this->logger->debug('Processcheck: Processes: ' . $processlist['amount'] . ' - Processlist: ' . $processlist['list']); + + if ($processlist['amount'] > $max_processes) { + $this->logger->debug('Processcheck: Maximum number of processes for ' . $process . ' tasks (' . $max_processes . ') reached.'); + return true; + } + } + return false; + */ + } + + /** + * @brief Checks if the minimal memory is reached + * + * @return bool Is the memory limit reached? + */ + public function isMinMemoryReached() + { + $min_memory = $this->config->get('system', 'min_memory', 0); + if ($min_memory == 0) { + return false; + } + + if (!is_readable('/proc/meminfo')) { + return false; + } + + $memdata = explode("\n", file_get_contents('/proc/meminfo')); + + $meminfo = []; + foreach ($memdata as $line) { + $data = explode(':', $line); + if (count($data) != 2) { + continue; + } + list($key, $val) = $data; + $meminfo[$key] = (int)trim(str_replace('kB', '', $val)); + $meminfo[$key] = (int)($meminfo[$key] / 1024); + } + + if (!isset($meminfo['MemFree'])) { + return false; + } + + $free = $meminfo['MemFree']; + + $reached = ($free < $min_memory); + + if ($reached) { + $this->logger->debug('Minimal memory reached.', ['free' => $free, 'memtotal' => $meminfo['MemTotal'], 'limit' => $min_memory]); + } + + return $reached; + } + + /** + * @brief Checks if the maximum load is reached + * + * @return bool Is the load reached? + */ + public function isMaxLoadReached() + { + if ($this->mode->isBackend()) { + $process = 'backend'; + $maxsysload = intval($this->config->get('system', 'maxloadavg')); + if ($maxsysload < 1) { + $maxsysload = 50; + } + } else { + $process = 'frontend'; + $maxsysload = intval($this->config->get('system', 'maxloadavg_frontend')); + if ($maxsysload < 1) { + $maxsysload = 50; + } + } + + $load = System::currentLoad(); + if ($load) { + if (intval($load) > $maxsysload) { + $this->logger->info('system load for process too high.', ['load' => $load, 'process' => $process, 'maxsysload' => $maxsysload]); + return true; + } + } + return false; + } + + /** + * Executes a child process with 'proc_open' + * + * @param string $command The command to execute + * @param array $args Arguments to pass to the command ( [ 'key' => value, 'key2' => value2, ... ] + */ + public function run($command, $args) + { + if (!function_exists('proc_open')) { + return; + } + + $cmdline = $this->config->get('config', 'php_path', 'php') . ' ' . escapeshellarg($command); + + foreach ($args as $key => $value) { + if (!is_null($value) && is_bool($value) && !$value) { + continue; + } + + $cmdline .= ' --' . $key; + if (!is_null($value) && !is_bool($value)) { + $cmdline .= ' ' . $value; + } + } + + if ($this->isMinMemoryReached()) { + return; + } + + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { + $resource = proc_open('cmd /c start /b ' . $cmdline, [], $foo, $this->basePath); + } else { + $resource = proc_open($cmdline . ' &', [], $foo, $this->basePath); + } + if (!is_resource($resource)) { + $this->logger->debug('We got no resource for command.', ['cmd' => $cmdline]); + return; + } + proc_close($resource); + } +} diff --git a/src/Core/Worker.php b/src/Core/Worker.php index d3299fe2b3..037590c90d 100644 --- a/src/Core/Worker.php +++ b/src/Core/Worker.php @@ -5,6 +5,7 @@ namespace Friendica\Core; use Friendica\BaseObject; +use Friendica\Core; use Friendica\Database\DBA; use Friendica\Model\Process; use Friendica\Util\DateTimeFormat; @@ -1082,7 +1083,9 @@ class Worker $args = ['no_cron' => !$do_cron]; - get_app()->proc_run($command, $args); + $a = get_app(); + $process = new Core\Process($a->getLogger(), $a->getMode(), $a->getConfig(), $a->getBasePath()); + $process->run($command, $args); // after spawning we have to remove the flag. if (Config::get('system', 'worker_daemon_mode', false)) { diff --git a/static/dependencies.config.php b/static/dependencies.config.php index 2183c94120..fc2da9c093 100644 --- a/static/dependencies.config.php +++ b/static/dependencies.config.php @@ -154,4 +154,9 @@ return [ ['determineModule', [], Dice::CHAIN_CALL], ], ], + Friendica\Core\Process::class => [ + 'constructParams' => [ + [Dice::INSTANCE => '$basepath'], + ], + ], ];