diff --git a/app/code/Magento/Cron/Console/Command/CronCommand.php b/app/code/Magento/Cron/Console/Command/CronCommand.php index 4032a74802652..4e8c4ea1a4404 100644 --- a/app/code/Magento/Cron/Console/Command/CronCommand.php +++ b/app/code/Magento/Cron/Console/Command/CronCommand.php @@ -1,7 +1,8 @@ create(Cron::class, ['parameters' => $params]); $cronObserver->launch(); - $output->writeln('' . 'Ran jobs by schedule.' . ''); + + // phpcs:ignore Magento2.Functions.DiscouragedFunction.Discouraged,Magento2.Exceptions.TryProcessSystemResources.MissingTryCatch + if (stream_isatty(STDOUT)) { + $output->writeln('' . 'Ran jobs by schedule.' . ''); + } return Cli::RETURN_SUCCESS; } diff --git a/app/code/Magento/Cron/Observer/ProcessCronQueueObserver.php b/app/code/Magento/Cron/Observer/ProcessCronQueueObserver.php index 230b24ef4471f..d000f7dbbeb31 100644 --- a/app/code/Magento/Cron/Observer/ProcessCronQueueObserver.php +++ b/app/code/Magento/Cron/Observer/ProcessCronQueueObserver.php @@ -1,7 +1,7 @@ getCronGroupConfigurationValue($groupId, 'use_separate_process') == 1 ) { $this->_shell->execute( - $phpPath . ' %s cron:run --group=' . $groupId . ' --' . Cli::INPUT_KEY_BOOTSTRAP . '=' + '%s %s cron:run --group=%s --' . Cli::INPUT_KEY_BOOTSTRAP . '=' . self::STANDALONE_PROCESS_STARTED . '=1', [ - BP . '/bin/magento' + $phpPath, + BP . '/bin/magento', + $groupId, ] ); continue; @@ -848,7 +850,7 @@ private function processPendingJobs(string $groupId, array $jobsRoot, int $curre /** @var Schedule $schedule */ foreach ($pendingJobs as $schedule) { if (isset($processedJobs[$schedule->getJobCode()])) { - // process only on job per run + // process only one of each job per run continue; } $jobConfig = isset($jobsRoot[$schedule->getJobCode()]) ? $jobsRoot[$schedule->getJobCode()] : null; diff --git a/app/code/Magento/Cron/Shell/CommandRendererBackground.php b/app/code/Magento/Cron/Shell/CommandRendererBackground.php new file mode 100644 index 0000000000000..c2234c668a355 --- /dev/null +++ b/app/code/Magento/Cron/Shell/CommandRendererBackground.php @@ -0,0 +1,47 @@ +filesystem->getDirectoryRead(DirectoryList::LOG)->getAbsolutePath(); + // @phpcs:ignore Magento2.Functions.DiscouragedFunction.Discouraged + $logFile = escapeshellarg($logDir . 'magento.cron.' . $groupId . '.log'); + } + + return $this->osInfo->isWindows() ? + 'start /B "magento background task" ' . $command + : str_replace('2>&1', ">> $logFile 2>&1 &", $command); + } +} diff --git a/app/code/Magento/Cron/Test/Unit/Console/Command/CronCommandTest.php b/app/code/Magento/Cron/Test/Unit/Console/Command/CronCommandTest.php index 83ebcddaf60b3..5d30cc88e1f62 100644 --- a/app/code/Magento/Cron/Test/Unit/Console/Command/CronCommandTest.php +++ b/app/code/Magento/Cron/Test/Unit/Console/Command/CronCommandTest.php @@ -1,8 +1,10 @@ objectManagerFactory, $this->deploymentConfigMock) ); $commandTester->execute([]); - $expectedMsg = 'Ran jobs by schedule.' . PHP_EOL; + $expectedMsg = ''; $this->assertEquals($expectedMsg, $commandTester->getDisplay()); } } diff --git a/app/code/Magento/Cron/Test/Unit/Shell/CommandRendererBackgroundTest.php b/app/code/Magento/Cron/Test/Unit/Shell/CommandRendererBackgroundTest.php new file mode 100644 index 0000000000000..238843a6df8fa --- /dev/null +++ b/app/code/Magento/Cron/Test/Unit/Shell/CommandRendererBackgroundTest.php @@ -0,0 +1,113 @@ +osInfo = $this->getMockBuilder(OsInfo::class) + ->getMock(); + + $directoryMock = $this->getMockBuilder(ReadInterface::class) + ->getMock(); + $directoryMock->expects($this->any()) + ->method('getAbsolutePath') + ->willReturn($this->logPath); + + $this->filesystem = $this->getMockBuilder(Filesystem::class) + ->disableOriginalConstructor() + ->getMock(); + $this->filesystem->expects($this->any()) + ->method('getDirectoryRead') + ->willReturn($directoryMock); + } + + /** + * @covers ::render + * @dataProvider commandPerOsTypeDataProvider + * + * @param bool $isWindows + * @param string $expectedResults + * @param string[] $arguments + */ + public function testRender($isWindows, $expectedResults, $arguments) + { + $this->osInfo->expects($this->once()) + ->method('isWindows') + ->willReturn($isWindows); + + $commandRenderer = new CommandRendererBackground($this->filesystem, $this->osInfo); + $this->assertEquals( + $expectedResults, + $commandRenderer->render($this->testCommand, $arguments) + ); + } + + /** + * Data provider for each os type + * + * @return array + */ + public function commandPerOsTypeDataProvider() + { + return [ + 'windows' => [ + true, + 'start /B "magento background task" ' . $this->testCommand . ' 2>&1', + [], + ], + 'unix-without-group-name' => [ + false, + $this->testCommand . ' >> /dev/null 2>&1 &', + [], + ], + 'unix-with-group-name' => [ + false, + $this->testCommand . " >> '{$this->logPath}magento.cron.group-name.log' 2>&1 &", + ['php-executable', 'script-path', 'group-name'], + ], + ]; + } +} diff --git a/app/code/Magento/Cron/etc/di.xml b/app/code/Magento/Cron/etc/di.xml index e7286169359bd..bcb11691753d6 100644 --- a/app/code/Magento/Cron/etc/di.xml +++ b/app/code/Magento/Cron/etc/di.xml @@ -1,8 +1,8 @@ @@ -28,15 +28,14 @@ - - + - Magento\Framework\Shell\CommandRendererBackground + Magento\Cron\Shell\CommandRendererBackground - shellBackground + shellBackgroundCron Magento\Cron\Model\VirtualLogger @@ -65,7 +64,7 @@ - {magentoRoot}bin/magento cron:run | grep -v "Ran jobs by schedule" >> {magentoLog}magento.cron.log + {magentoRoot}bin/magento cron:run >> {magentoLog}magento.cron.log 2>&1 false diff --git a/app/etc/di.xml b/app/etc/di.xml index 385518fd79a20..11c174fffdfb8 100644 --- a/app/etc/di.xml +++ b/app/etc/di.xml @@ -2014,4 +2014,11 @@ + + + + + Magento\Framework\Shell\CommandRendererBackground + +