diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminApplyChangePriceForConfigurableProductWithAssignedSimpleProductsTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminApplyChangePriceForConfigurableProductWithAssignedSimpleProductsTest.xml index cfaf0c4b88ad3..daf3ff5b824bd 100755 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminApplyChangePriceForConfigurableProductWithAssignedSimpleProductsTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminApplyChangePriceForConfigurableProductWithAssignedSimpleProductsTest.xml @@ -80,7 +80,10 @@ - + + diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCheckConfigurableProductPriceWhenChildProductPriceUpdatedTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCheckConfigurableProductPriceWhenChildProductPriceUpdatedTest.xml index 806366a7ad57e..926e7e9767d89 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCheckConfigurableProductPriceWhenChildProductPriceUpdatedTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCheckConfigurableProductPriceWhenChildProductPriceUpdatedTest.xml @@ -166,7 +166,10 @@ - + + diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontVerifyProductAfterPartialReindexOnSeveralWebsitesTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontVerifyProductAfterPartialReindexOnSeveralWebsitesTest.xml index e5f464920c3ee..a1d5b0fd537c3 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontVerifyProductAfterPartialReindexOnSeveralWebsitesTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontVerifyProductAfterPartialReindexOnSeveralWebsitesTest.xml @@ -82,7 +82,10 @@ - + + diff --git a/app/code/Magento/Cron/Console/Command/CronCommand.php b/app/code/Magento/Cron/Console/Command/CronCommand.php index 4032a74802652..ceb123724210f 100644 --- a/app/code/Magento/Cron/Console/Command/CronCommand.php +++ b/app/code/Magento/Cron/Console/Command/CronCommand.php @@ -1,4 +1,5 @@ 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 14d9a599ae011..def320ab83636 100644 --- a/app/code/Magento/Cron/Observer/ProcessCronQueueObserver.php +++ b/app/code/Magento/Cron/Observer/ProcessCronQueueObserver.php @@ -278,10 +278,12 @@ function ($a, $b) { && $this->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; @@ -854,7 +856,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..b8f792b9c0a25 --- /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..8718771432d0b 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..02358ca464069 --- /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..73795e43a2640 100644 --- a/app/code/Magento/Cron/etc/di.xml +++ b/app/code/Magento/Cron/etc/di.xml @@ -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 c74ce0d679439..19bcc8a875cb9 100644 --- a/app/etc/di.xml +++ b/app/etc/di.xml @@ -2008,4 +2008,10 @@ + + + + Magento\Framework\Shell\CommandRendererBackground + +