Skip to content

Commit c6503d4

Browse files
author
Oleksii Korshenko
authored
Merge pull request #1217 from magento-engcom/develop-prs
Public Pull Requests #9994 #9957 #9939 #8784
2 parents 4866d5f + c287293 commit c6503d4

File tree

6 files changed

+409
-408
lines changed

6 files changed

+409
-408
lines changed

app/code/Magento/Cron/Observer/ProcessCronQueueObserver.php

Lines changed: 108 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,16 @@ class ProcessCronQueueObserver implements ObserverInterface
116116
*/
117117
private $state;
118118

119+
/**
120+
* @var array
121+
*/
122+
private $invalid = [];
123+
124+
/**
125+
* @var array
126+
*/
127+
private $jobs;
128+
119129
/**
120130
* @param \Magento\Framework\ObjectManagerInterface $objectManager
121131
* @param \Magento\Cron\Model\ScheduleFactory $scheduleFactory
@@ -176,17 +186,21 @@ public function execute(\Magento\Framework\Event\Observer $observer)
176186
$phpPath = $this->phpExecutableFinder->find() ?: 'php';
177187

178188
foreach ($jobGroupsRoot as $groupId => $jobsRoot) {
189+
$this->_cleanup($groupId);
190+
$this->_generate($groupId);
179191
if ($this->_request->getParam('group') !== null
180192
&& $this->_request->getParam('group') !== '\'' . ($groupId) . '\''
181-
&& $this->_request->getParam('group') !== $groupId) {
193+
&& $this->_request->getParam('group') !== $groupId
194+
) {
182195
continue;
183196
}
184197
if (($this->_request->getParam(self::STANDALONE_PROCESS_STARTED) !== '1') && (
185198
$this->_scopeConfig->getValue(
186199
'system/cron/' . $groupId . '/use_separate_process',
187200
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
188201
) == 1
189-
)) {
202+
)
203+
) {
190204
$this->_shell->execute(
191205
$phpPath . ' %s cron:run --group=' . $groupId . ' --' . Cli::INPUT_KEY_BOOTSTRAP . '='
192206
. self::STANDALONE_PROCESS_STARTED . '=1',
@@ -197,6 +211,7 @@ public function execute(\Magento\Framework\Event\Observer $observer)
197211
continue;
198212
}
199213

214+
/** @var \Magento\Cron\Model\Schedule $schedule */
200215
foreach ($pendingJobs as $schedule) {
201216
$jobConfig = isset($jobsRoot[$schedule->getJobCode()]) ? $jobsRoot[$schedule->getJobCode()] : null;
202217
if (!$jobConfig) {
@@ -232,9 +247,6 @@ public function execute(\Magento\Framework\Event\Observer $observer)
232247
}
233248
$schedule->save();
234249
}
235-
236-
$this->_generate($groupId);
237-
$this->_cleanup($groupId);
238250
}
239251
}
240252

@@ -336,8 +348,10 @@ protected function _generate($groupId)
336348
/**
337349
* generate global crontab jobs
338350
*/
339-
$jobs = $this->_config->getJobs();
351+
$jobs = $this->getJobs();
352+
$this->invalid = [];
340353
$this->_generateJobs($jobs[$groupId], $exists, $groupId);
354+
$this->cleanupScheduleMismatches();
341355

342356
/**
343357
* save time schedules generation was ran with no expiration
@@ -363,17 +377,7 @@ protected function _generate($groupId)
363377
protected function _generateJobs($jobs, $exists, $groupId)
364378
{
365379
foreach ($jobs as $jobCode => $jobConfig) {
366-
$cronExpression = null;
367-
if (isset($jobConfig['config_path'])) {
368-
$cronExpression = $this->getConfigSchedule($jobConfig) ?: null;
369-
}
370-
371-
if (!$cronExpression) {
372-
if (isset($jobConfig['schedule'])) {
373-
$cronExpression = $jobConfig['schedule'];
374-
}
375-
}
376-
380+
$cronExpression = $this->getCronExpression($jobConfig);
377381
if (!$cronExpression) {
378382
continue;
379383
}
@@ -385,13 +389,15 @@ protected function _generateJobs($jobs, $exists, $groupId)
385389
}
386390

387391
/**
388-
* Clean existed jobs
392+
* Clean expired jobs
389393
*
390394
* @param string $groupId
391395
* @return $this
392396
*/
393397
protected function _cleanup($groupId)
394398
{
399+
$this->cleanupDisabledJobs($groupId);
400+
395401
// check if history cleanup is needed
396402
$lastCleanup = (int)$this->_cache->load(self::CACHE_KEY_LAST_HISTORY_CLEANUP_AT . $groupId);
397403
$historyCleanUp = (int)$this->_scopeConfig->getValue(
@@ -478,13 +484,20 @@ protected function saveSchedule($jobCode, $cronExpression, $timeInterval, $exist
478484
$currentTime = $this->dateTime->gmtTimestamp();
479485
$timeAhead = $currentTime + $timeInterval;
480486
for ($time = $currentTime; $time < $timeAhead; $time += self::SECONDS_IN_MINUTE) {
481-
$ts = strftime('%Y-%m-%d %H:%M:00', $time);
482-
if (!empty($exists[$jobCode . '/' . $ts])) {
483-
// already scheduled
487+
$scheduledAt = strftime('%Y-%m-%d %H:%M:00', $time);
488+
$alreadyScheduled = !empty($exists[$jobCode . '/' . $scheduledAt]);
489+
$schedule = $this->generateSchedule($jobCode, $cronExpression, $time);
490+
$valid = $schedule->trySchedule();
491+
if (!$valid) {
492+
if ($alreadyScheduled) {
493+
if (!isset($this->invalid[$jobCode])) {
494+
$this->invalid[$jobCode] = [];
495+
}
496+
$this->invalid[$jobCode][] = $scheduledAt;
497+
}
484498
continue;
485499
}
486-
$schedule = $this->generateSchedule($jobCode, $cronExpression, $time);
487-
if ($schedule->trySchedule()) {
500+
if (!$alreadyScheduled) {
488501
// time matches cron expression
489502
$schedule->save();
490503
}
@@ -523,4 +536,76 @@ protected function getScheduleTimeInterval($groupId)
523536

524537
return $scheduleAheadFor;
525538
}
539+
540+
/**
541+
* Clean up scheduled jobs that are disabled in the configuration
542+
* This can happen when you turn off a cron job in the config and flush the cache
543+
*
544+
* @param string $groupId
545+
* @return void
546+
*/
547+
private function cleanupDisabledJobs($groupId)
548+
{
549+
$jobs = $this->getJobs();
550+
foreach ($jobs[$groupId] as $jobCode => $jobConfig) {
551+
if (!$this->getCronExpression($jobConfig)) {
552+
/** @var \Magento\Cron\Model\ResourceModel\Schedule $scheduleResource */
553+
$scheduleResource = $this->_scheduleFactory->create()->getResource();
554+
$scheduleResource->getConnection()->delete($scheduleResource->getMainTable(), [
555+
'status=?' => Schedule::STATUS_PENDING,
556+
'job_code=?' => $jobCode,
557+
]);
558+
}
559+
}
560+
}
561+
562+
/**
563+
* @param array $jobConfig
564+
* @return null|string
565+
*/
566+
private function getCronExpression($jobConfig)
567+
{
568+
$cronExpression = null;
569+
if (isset($jobConfig['config_path'])) {
570+
$cronExpression = $this->getConfigSchedule($jobConfig) ?: null;
571+
}
572+
573+
if (!$cronExpression) {
574+
if (isset($jobConfig['schedule'])) {
575+
$cronExpression = $jobConfig['schedule'];
576+
}
577+
}
578+
return $cronExpression;
579+
}
580+
581+
/**
582+
* Clean up scheduled jobs that do not match their cron expression anymore
583+
* This can happen when you change the cron expression and flush the cache
584+
*
585+
* @return $this
586+
*/
587+
private function cleanupScheduleMismatches()
588+
{
589+
foreach ($this->invalid as $jobCode => $scheduledAtList) {
590+
/** @var \Magento\Cron\Model\ResourceModel\Schedule $scheduleResource */
591+
$scheduleResource = $this->_scheduleFactory->create()->getResource();
592+
$scheduleResource->getConnection()->delete($scheduleResource->getMainTable(), [
593+
'status=?' => Schedule::STATUS_PENDING,
594+
'job_code=?' => $jobCode,
595+
'scheduled_at in (?)' => $scheduledAtList,
596+
]);
597+
}
598+
return $this;
599+
}
600+
601+
/**
602+
* @return array
603+
*/
604+
private function getJobs()
605+
{
606+
if ($this->jobs === null) {
607+
$this->jobs = $this->_config->getJobs();
608+
}
609+
return $this->jobs;
610+
}
526611
}

0 commit comments

Comments
 (0)