Skip to content

Unable to manage (install/uninstall) cron via bin/magento cron:install / cron:remove with multiple installations against same crontab #11360

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/code/Magento/Cron/etc/di.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
</argument>
</arguments>
</type>
<type name="Magento\Framework\Crontab\CrontabManager">
<type name="Magento\Framework\Crontab\CrontabManagerInterface">
<arguments>
<argument name="shell" xsi:type="object">Magento\Framework\App\Shell</argument>
</arguments>
Expand Down
51 changes: 38 additions & 13 deletions lib/internal/Magento/Framework/Crontab/CrontabManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
*/
namespace Magento\Framework\Crontab;

use Magento\Framework\ShellInterface;
use Magento\Framework\Phrase;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Filesystem;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Phrase;
use Magento\Framework\ShellInterface;

/**
* Manager works with cron tasks
Expand Down Expand Up @@ -38,14 +38,38 @@ public function __construct(
$this->filesystem = $filesystem;
}

/**
* @return string
*/
private function getTasksBlockStart()
{
$tasksBlockStart = self::TASKS_BLOCK_START;
if (defined('BP')) {
$tasksBlockStart .= ' ' . md5(BP);
}
return $tasksBlockStart;
}

/**
* @return string
*/
private function getTasksBlockEnd()
{
$tasksBlockEnd = self::TASKS_BLOCK_END;
if (defined('BP')) {
$tasksBlockEnd .= ' ' . md5(BP);
}
return $tasksBlockEnd;
}

/**
* {@inheritdoc}
*/
public function getTasks()
{
$this->checkSupportedOs();
$content = $this->getCrontabContent();
$pattern = '!(' . self::TASKS_BLOCK_START . ')(.*?)(' . self::TASKS_BLOCK_END . ')!s';
$pattern = '!(' . $this->getTasksBlockStart() . ')(.*?)(' . $this->getTasksBlockEnd() . ')!s';

if (preg_match($pattern, $content, $matches)) {
$tasks = trim($matches[2], PHP_EOL);
Expand All @@ -61,14 +85,14 @@ public function getTasks()
*/
public function saveTasks(array $tasks)
{
$this->checkSupportedOs();
$baseDir = $this->filesystem->getDirectoryRead(DirectoryList::ROOT)->getAbsolutePath();
$logDir = $this->filesystem->getDirectoryRead(DirectoryList::LOG)->getAbsolutePath();

if (!$tasks) {
throw new LocalizedException(new Phrase('List of tasks is empty'));
}

$this->checkSupportedOs();
$baseDir = $this->filesystem->getDirectoryRead(DirectoryList::ROOT)->getAbsolutePath();
$logDir = $this->filesystem->getDirectoryRead(DirectoryList::LOG)->getAbsolutePath();

foreach ($tasks as $key => $task) {
if (empty($task['expression'])) {
$tasks[$key]['expression'] = '* * * * *';
Expand Down Expand Up @@ -114,11 +138,11 @@ public function removeTasks()
private function generateSection($content, $tasks = [])
{
if ($tasks) {
$content .= self::TASKS_BLOCK_START . PHP_EOL;
$content .= $this->getTasksBlockStart() . PHP_EOL;
foreach ($tasks as $task) {
$content .= $task['expression'] . ' ' . PHP_BINARY . ' '. $task['command'] . PHP_EOL;
$content .= $task['expression'] . ' ' . PHP_BINARY . ' ' . $task['command'] . PHP_EOL;
}
$content .= self::TASKS_BLOCK_END . PHP_EOL;
$content .= $this->getTasksBlockEnd() . PHP_EOL;
}

return $content;
Expand All @@ -133,7 +157,8 @@ private function generateSection($content, $tasks = [])
private function cleanMagentoSection($content)
{
$content = preg_replace(
'!' . preg_quote(self::TASKS_BLOCK_START) . '.*?' . preg_quote(self::TASKS_BLOCK_END . PHP_EOL) . '!s',
'!' . preg_quote($this->getTasksBlockStart()) . '.*?'
. preg_quote($this->getTasksBlockEnd() . PHP_EOL) . '!s',
'',
$content
);
Expand Down Expand Up @@ -192,7 +217,7 @@ private function checkSupportedOs()
{
if (stripos(PHP_OS, 'WIN') === 0) {
throw new LocalizedException(
new Phrase('Your operation system is not supported to work with this command')
new Phrase('Your operating system is not supported to work with this command')
);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,17 +87,17 @@ public function getTasksDataProvider()
return [
[
'content' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL
. CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL
. CrontabManagerInterface::TASKS_BLOCK_START . ' ' . md5(BP) . PHP_EOL
. '* * * * * /bin/php /var/www/magento/bin/magento cron:run' . PHP_EOL
. CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL,
. CrontabManagerInterface::TASKS_BLOCK_END . ' ' . md5(BP) . PHP_EOL,
'tasks' => ['* * * * * /bin/php /var/www/magento/bin/magento cron:run'],
],
[
'content' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL
. CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL
. CrontabManagerInterface::TASKS_BLOCK_START . ' ' . md5(BP) . PHP_EOL
. '* * * * * /bin/php /var/www/magento/bin/magento cron:run' . PHP_EOL
. '* * * * * /bin/php /var/www/magento/bin/magento setup:cron:run' . PHP_EOL
. CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL,
. CrontabManagerInterface::TASKS_BLOCK_END . ' ' . md5(BP) . PHP_EOL,
'tasks' => [
'* * * * * /bin/php /var/www/magento/bin/magento cron:run',
'* * * * * /bin/php /var/www/magento/bin/magento setup:cron:run',
Expand Down Expand Up @@ -165,17 +165,17 @@ public function removeTasksDataProvider()
return [
[
'contentBefore' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL
. CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL
. CrontabManagerInterface::TASKS_BLOCK_START . ' ' . md5(BP) . PHP_EOL
. '* * * * * /bin/php /var/www/magento/bin/magento cron:run' . PHP_EOL
. CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL,
. CrontabManagerInterface::TASKS_BLOCK_END . ' ' . md5(BP) . PHP_EOL,
'contentAfter' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL
],
[
'contentBefore' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL
. CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL
. CrontabManagerInterface::TASKS_BLOCK_START . ' ' . md5(BP) . PHP_EOL
. '* * * * * /bin/php /var/www/magento/bin/magento cron:run' . PHP_EOL
. '* * * * * /bin/php /var/www/magento/bin/magento setup:cron:run' . PHP_EOL
. CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL,
. CrontabManagerInterface::TASKS_BLOCK_END . ' ' . md5(BP) . PHP_EOL,
'contentAfter' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL
],
[
Expand All @@ -198,14 +198,13 @@ public function testSaveTasksWithEmptyTasksList()
{
$baseDirMock = $this->getMockBuilder(ReadInterface::class)
->getMockForAbstractClass();
$baseDirMock->expects($this->once())
$baseDirMock->expects($this->never())
->method('getAbsolutePath')
->willReturn('/var/www/magento2/');
$logDirMock = $this->getMockBuilder(ReadInterface::class)
->getMockForAbstractClass();
$logDirMock->expects($this->once())
->method('getAbsolutePath')
->willReturn('/var/www/magento2/var/log/');
$logDirMock->expects($this->never())
->method('getAbsolutePath');

$this->filesystemMock->expects($this->any())
->method('getDirectoryRead')
Expand Down Expand Up @@ -292,9 +291,9 @@ public function testSaveTasks($tasks, $content, $contentToSave)
public function saveTasksDataProvider()
{
$content = '* * * * * /bin/php /var/www/cron.php' . PHP_EOL
. CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL
. CrontabManagerInterface::TASKS_BLOCK_START . ' ' . md5(BP) . PHP_EOL
. '* * * * * /bin/php /var/www/magento/bin/magento cron:run' . PHP_EOL
. CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL;
. CrontabManagerInterface::TASKS_BLOCK_END . ' ' . md5(BP) . PHP_EOL;

return [
[
Expand All @@ -303,41 +302,41 @@ public function saveTasksDataProvider()
],
'content' => $content,
'contentToSave' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL
. CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL
. CrontabManagerInterface::TASKS_BLOCK_START . ' ' . md5(BP) . PHP_EOL
. '* * * * * ' . PHP_BINARY . ' run.php' . PHP_EOL
. CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL,
. CrontabManagerInterface::TASKS_BLOCK_END . ' ' . md5(BP) . PHP_EOL,
],
[
'tasks' => [
['expression' => '1 2 3 4 5', 'command' => 'run.php']
],
'content' => $content,
'contentToSave' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL
. CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL
. CrontabManagerInterface::TASKS_BLOCK_START . ' ' . md5(BP) . PHP_EOL
. '1 2 3 4 5 ' . PHP_BINARY . ' run.php' . PHP_EOL
. CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL,
. CrontabManagerInterface::TASKS_BLOCK_END . ' ' . md5(BP) . PHP_EOL,
],
[
'tasks' => [
['command' => '{magentoRoot}run.php >> {magentoLog}cron.log']
],
'content' => $content,
'contentToSave' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL
. CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL
. CrontabManagerInterface::TASKS_BLOCK_START . ' ' . md5(BP) . PHP_EOL
. '* * * * * ' . PHP_BINARY . ' /var/www/magento2/run.php >>'
. ' /var/www/magento2/var/log/cron.log' . PHP_EOL
. CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL,
. CrontabManagerInterface::TASKS_BLOCK_END . ' ' . md5(BP) . PHP_EOL,
],
[
'tasks' => [
['command' => '{magentoRoot}run.php % cron:run | grep -v "Ran \'jobs\' by schedule"']
],
'content' => $content,
'contentToSave' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL
. CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL
. CrontabManagerInterface::TASKS_BLOCK_START . ' ' . md5(BP) . PHP_EOL
. '* * * * * ' . PHP_BINARY . ' /var/www/magento2/run.php'
. ' %% cron:run | grep -v \"Ran \'jobs\' by schedule\"' . PHP_EOL
. CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL,
. CrontabManagerInterface::TASKS_BLOCK_END . ' ' . md5(BP) . PHP_EOL,
],
];
}
Expand Down