From 1dbb3815e38a951043667e4a7ce2b5b062ec512b Mon Sep 17 00:00:00 2001 From: Alfred Bez <1001186+alfredbez@users.noreply.github.com> Date: Mon, 26 Oct 2026 06:26:11 +0000 Subject: [PATCH] fix(parallel): report error limit only when reached Keep worker shutdown unchanged; derive its diagnostic flag from the error count. Amp-Thread-ID: https://ampcode.com/threads/T-01a16d84-bc27-70ae-85cc-28b404cfd024 Co-authored-by: Amp --- .../Application/ParallelFileProcessor.php | 2 +- tests/Bin/Fixture/ParallelTimeout/Timeout.php | 3 ++ tests/Bin/Fixture/TimeoutRector.php | 39 ++++++++++++++ tests/Bin/RectorTest.php | 54 +++++++++++++++++++ tests/Bin/config/parallel-worker-timeout.php | 14 +++++ 5 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 tests/Bin/Fixture/ParallelTimeout/Timeout.php create mode 100644 tests/Bin/Fixture/TimeoutRector.php create mode 100644 tests/Bin/config/parallel-worker-timeout.php diff --git a/src/Parallel/Application/ParallelFileProcessor.php b/src/Parallel/Application/ParallelFileProcessor.php index ccce30cc841..90f47fc354c 100644 --- a/src/Parallel/Application/ParallelFileProcessor.php +++ b/src/Parallel/Application/ParallelFileProcessor.php @@ -132,7 +132,7 @@ public function process( )); ++$systemErrorsCount; - $reachedSystemErrorsCountLimit = true; + $reachedSystemErrorsCountLimit = $systemErrorsCount >= self::SYSTEM_ERROR_LIMIT; $this->processPool->quitAll(); // give the child processes time to actually die, they can still write to cache meanwhile diff --git a/tests/Bin/Fixture/ParallelTimeout/Timeout.php b/tests/Bin/Fixture/ParallelTimeout/Timeout.php new file mode 100644 index 00000000000..1126ab00d0e --- /dev/null +++ b/tests/Bin/Fixture/ParallelTimeout/Timeout.php @@ -0,0 +1,3 @@ +> + */ + public function getNodeTypes(): array + { + return [FuncCall::class]; + } + + /** + * @param FuncCall $node + */ + public function refactor(Node $node): ?Node + { + if ($this->isName($node, 'pause')) { + sleep(10); + } + + return null; + } +} diff --git a/tests/Bin/RectorTest.php b/tests/Bin/RectorTest.php index 44658f11723..ded8dfa0020 100644 --- a/tests/Bin/RectorTest.php +++ b/tests/Bin/RectorTest.php @@ -41,4 +41,58 @@ public function testConsoleOutput(string $command, string $expectedOutput): void $process->getErrorOutput() )); } + + /** + * @return Iterator + */ + public static function provideParallelTimeouts(): Iterator + { + yield 'one timeout below the limit' => [0, [ + 'Child process timed out after 1 seconds', + 'Some parallel jobs have not finished, results for 1 of 1 files are missing', + ]]; + + yield '49 errors followed by a timeout reach the limit' => [49, [ + ...array_fill(0, 49, "Syntax error, unexpected ';'"), + 'Child process timed out after 1 seconds', + 'Reached system errors count limit of 50, exiting...', + 'Some parallel jobs have not finished, results for 1 of 50 files are missing', + ]]; + } + + /** + * @param string[] $expectedMessages + */ + #[DataProvider('provideParallelTimeouts')] + public function testParallelTimeoutReportsErrorLimitOnlyWhenReached( + int $previousErrorCount, + array $expectedMessages + ): void { + $filePaths = []; + for ($i = 5; $i < 5 + $previousErrorCount; ++$i) { + $filePaths[] = __DIR__ . sprintf('/../../e2e/parallel-system-errors-limit/src/File%02d.php', $i); + } + + // The syntax-error files are larger, so the single worker processes them before the timeout file. + $filePaths[] = __DIR__ . '/Fixture/ParallelTimeout/Timeout.php'; + + $process = new Process([ + PHP_BINARY, + 'bin/rector', + '--config', + __DIR__ . '/config/parallel-worker-timeout.php', + '--dry-run', + '--clear-cache', + '--no-progress-bar', + '--output-format=json', + ...$filePaths, + ]); + $process->setTimeout(20); + $process->run(); + + $this->assertSame(1, $process->getExitCode(), $process->getOutput() . $process->getErrorOutput()); + $result = json_decode($process->getOutput(), true, flags: JSON_THROW_ON_ERROR); + $this->assertSame(count($expectedMessages), $result['totals']['errors']); + $this->assertSame($expectedMessages, array_column($result['errors'], 'message')); + } } diff --git a/tests/Bin/config/parallel-worker-timeout.php b/tests/Bin/config/parallel-worker-timeout.php new file mode 100644 index 00000000000..f540fc6fb99 --- /dev/null +++ b/tests/Bin/config/parallel-worker-timeout.php @@ -0,0 +1,14 @@ +paths([__DIR__ . '/../Fixture/ParallelTimeout']); + $rectorConfig->parallel(processTimeout: 1, maxNumberOfProcess: 1, jobSize: 1); + $rectorConfig->rules([TimeoutRector::class]); +};