[DX] Add --memory-limit option to pass memory limit to parallel subprocesses (#1726)

This commit is contained in:
Tomas Votruba 2022-01-25 12:45:18 +01:00 committed by GitHub
parent caeeb78f6f
commit 1869c1dc00
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 73 additions and 1 deletions

View File

@ -49,6 +49,9 @@ final class ConfigurationFactory
$parallelPort = (string) $input->getOption(Option::PARALLEL_PORT);
$parallelIdentifier = (string) $input->getOption(Option::PARALLEL_IDENTIFIER);
/** @var string|null $memoryLimit */
$memoryLimit = $input->getOption(Option::MEMORY_LIMIT);
return new Configuration(
$isDryRun,
$showProgressBar,
@ -59,7 +62,8 @@ final class ConfigurationFactory
$showDiffs,
$parallelPort,
$parallelIdentifier,
$isParallel
$isParallel,
$memoryLimit
);
}

View File

@ -215,4 +215,9 @@ final class Option
* @var string
*/
final public const FOLLOW_SYMLINKS = 'follow-symlinks';
/**
* @var string
*/
final public const MEMORY_LIMIT = 'memory-limit';
}

View File

@ -66,6 +66,8 @@ abstract class AbstractProcessCommand extends Command
ConsoleOutputFormatter::NAME
);
$this->addOption(Option::MEMORY_LIMIT, null, InputOption::VALUE_REQUIRED, 'Memory limit for process',);
$this->addOption(Option::CLEAR_CACHE, null, InputOption::VALUE_NONE, 'Clear unchaged files cache');
$this->addOption(Option::PARALLEL_PORT, null, InputOption::VALUE_REQUIRED);

View File

@ -15,6 +15,7 @@ use Rector\Core\Contract\Rector\RectorInterface;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\Reporting\MissingRectorRulesReporter;
use Rector\Core\StaticReflection\DynamicSourceLocatorDecorator;
use Rector\Core\Util\MemoryLimiter;
use Rector\Core\Validation\EmptyConfigurableRectorChecker;
use Rector\Core\ValueObject\Configuration;
use Rector\Core\ValueObject\ProcessResult;
@ -44,6 +45,7 @@ final class ProcessCommand extends AbstractProcessCommand
private readonly EmptyConfigurableRectorChecker $emptyConfigurableRectorChecker,
private readonly OutputFormatterCollector $outputFormatterCollector,
private readonly SymfonyStyle $symfonyStyle,
private readonly MemoryLimiter $memoryLimiter,
private readonly array $rectors
) {
parent::__construct();
@ -65,6 +67,7 @@ final class ProcessCommand extends AbstractProcessCommand
}
$configuration = $this->configurationFactory->createFromInput($input);
$this->memoryLimiter->adjust($configuration);
// disable console output in case of json output formatter
if ($configuration->getOutputFormat() === JsonOutputFormatter::NAME) {

View File

@ -9,6 +9,7 @@ use Clue\React\NDJson\Encoder;
use React\EventLoop\StreamSelectLoop;
use React\Socket\ConnectionInterface;
use React\Socket\TcpConnector;
use Rector\Core\Util\MemoryLimiter;
use Rector\Parallel\WorkerRunner;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
@ -27,6 +28,7 @@ final class WorkerCommand extends AbstractProcessCommand
{
public function __construct(
private readonly WorkerRunner $workerRunner,
private readonly MemoryLimiter $memoryLimiter,
) {
parent::__construct();
}
@ -41,6 +43,7 @@ final class WorkerCommand extends AbstractProcessCommand
protected function execute(InputInterface $input, OutputInterface $output): int
{
$configuration = $this->configurationFactory->createFromInput($input);
$this->memoryLimiter->adjust($configuration);
$streamSelectLoop = new StreamSelectLoop();
$parallelIdentifier = $configuration->getParallelIdentifier();

View File

@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
namespace Rector\Core\Util;
use Nette\Utils\Strings;
use Rector\Core\ValueObject\Configuration;
use Rector\RectorGenerator\Exception\ConfigurationException;
/**
* @inspiration https://github.com/phpstan/phpstan-src/commit/ccc046ca473dcdb5ce9225cc05d7808f2e327f40
*/
final class MemoryLimiter
{
/**
* @var string
* @see https://regex101.com/r/pmiGUM/1
*/
private const VALID_MEMORY_LIMIT_REGEX = '#^-?\d+[kMG]?$#i';
public function adjust(Configuration $configuration): void
{
$memoryLimit = $configuration->getMemoryLimit();
if ($memoryLimit === null) {
return;
}
$this->validateMemoryLimitFormat($memoryLimit);
$memorySetResult = ini_set('memory_limit', $memoryLimit);
if ($memorySetResult === false) {
$errorMessage = sprintf('Memory limit "%s" cannot be set.', $memoryLimit);
throw new ConfigurationException($errorMessage);
}
}
private function validateMemoryLimitFormat(string $memoryLimit): void
{
$memoryLimitFormatMatch = Strings::match($memoryLimit, self::VALID_MEMORY_LIMIT_REGEX);
if ($memoryLimitFormatMatch !== null) {
return;
}
$errorMessage = sprintf('Invalid memory limit format "%s".', $memoryLimit);
throw new ConfigurationException($errorMessage);
}
}

View File

@ -25,6 +25,7 @@ final class Configuration
private readonly string | null $parallelPort = null,
private readonly string | null $parallelIdentifier = null,
private readonly bool $isParallel = false,
private readonly string|null $memoryLimit = null
) {
}
@ -83,4 +84,9 @@ final class Configuration
{
return $this->isParallel;
}
public function getMemoryLimit(): ?string
{
return $this->memoryLimit;
}
}