Skip to content

Fix --parallel workers ignoring memory_limit - #497

Open
abodnar wants to merge 1 commit into
laravel:mainfrom
abodnar:forward-memory-limit-to-parallel-workers
Open

abodnar wants to merge 1 commit into
laravel:mainfrom
abodnar:forward-memory-limit-to-parallel-workers

Conversation

@abodnar

@abodnar abodnar commented Oct 16, 2026

Copy link
Copy Markdown

When pint runs with --parallel, the workers are started as php <pint> worker --port ... and none of the parent's ini settings are passed along. So php -d memory_limit=1G vendor/bin/pint --parallel only raises the limit for the parent, and every worker still runs at the default (128M on the official PHP images).

That would mostly be a performance problem, except a worker that runs out of memory dies with a fatal on stderr and the parent drops that worker's whole chunk without treating it as an error. The run exits 0 and reports nothing, so --test passes in CI with violations in the tree. We ran into this on a project with a 3.3MB data migration, and the pint job had been passing with style violations for a while before anyone noticed. The silent exit 0 is already open upstream as PHP-CS-Fixer/PHP-CS-Fixer#9854. This PR only covers the memory limit not reaching the workers, since that part lives in Pint's own override of ProcessFactory.

The fix has getCommandArgs() in overrides/Runner/Parallel/ProcessFactory.php add -d memory_limit= with the parent's ini_get('memory_limit') value right after the PHP binary. Workers now run with whatever limit the parent was started with. If nobody set one, the workers get the same default they would have had anyway.

tests/Unit/Overrides/ProcessFactoryTest.php sets the limit to 1536M and checks that the worker args come out as -d memory_limit=1536M right after the binary. Nothing else about how workers are started changes. If no limit was set, or it's -1, the worker just gets the same value it would have picked up from php.ini anyway, so I don't think anything existing would behave differently.

The workaround until now has been putting memory_limit=1024M in an ini file and setting PHP_INI_SCAN_DIR=:<that dir>, since the workers do inherit the environment. That works, but I don't think anyone would expect to need it when they're already passing -d memory_limit.

Reproducing

composer.json:

{ "require-dev": { "laravel/pint": "1.32.1" } }

generate.php:

<?php
    $lines = ["<?php", "", "return ["];
    for ($index = 0; $index < 60000; $index++) {
        $lines[] = "    'key_$index' => 'value_$index',";
    }
    $lines[] = "];";
    is_dir('src') || mkdir('src');
    file_put_contents('src/large.php', implode("\n", $lines)."\n");
    file_put_contents('src/large_with_violation.php', implode("\n", $lines)."\n\$probe=!true;\n");
    file_put_contents('src/small_with_violation.php', "<?php\n\n\$probe=!true;\n");
composer install
php generate.php
php -d memory_limit=1G vendor/bin/pint --parallel --test src

Before this change it exits 0 and reports nothing. With it, it exits 1 and reports src/small_with_violation.php and src/large_with_violation.php, which matches the sequential run.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant