@@ -109,12 +109,17 @@ class ProcessCronQueueObserver implements ObserverInterface
109
109
/**
110
110
* @var \Psr\Log\LoggerInterface
111
111
*/
112
- private $ logger ;
112
+ protected $ logger ;
113
113
114
114
/**
115
115
* @var \Magento\Framework\App\State
116
116
*/
117
- private $ state ;
117
+ protected $ state ;
118
+
119
+ /**
120
+ * @var array
121
+ */
122
+ protected $ invalid = [];
118
123
119
124
/**
120
125
* @param \Magento\Framework\ObjectManagerInterface $objectManager
@@ -180,15 +185,17 @@ public function execute(\Magento\Framework\Event\Observer $observer)
180
185
$ this ->generate ($ groupId );
181
186
if ($ this ->request ->getParam ('group ' ) !== null
182
187
&& $ this ->request ->getParam ('group ' ) !== '\'' . ($ groupId ) . '\''
183
- && $ this ->request ->getParam ('group ' ) !== $ groupId ) {
188
+ && $ this ->request ->getParam ('group ' ) !== $ groupId
189
+ ) {
184
190
continue ;
185
191
}
186
192
if (($ this ->request ->getParam (self ::STANDALONE_PROCESS_STARTED ) !== '1 ' ) && (
187
193
$ this ->scopeConfig ->getValue (
188
194
'system/cron/ ' . $ groupId . '/use_separate_process ' ,
189
195
\Magento \Store \Model \ScopeInterface::SCOPE_STORE
190
196
) == 1
191
- )) {
197
+ )
198
+ ) {
192
199
$ this ->shell ->execute (
193
200
$ phpPath . ' %s cron:run --group= ' . $ groupId . ' -- ' . Cli::INPUT_KEY_BOOTSTRAP . '= '
194
201
. self ::STANDALONE_PROCESS_STARTED . '=1 ' ,
@@ -336,7 +343,9 @@ public function generate($groupId)
336
343
* generate global crontab jobs
337
344
*/
338
345
$ jobs = $ this ->config ->getJobs ();
346
+ $ this ->invalid = [];
339
347
$ this ->generateJobs ($ jobs [$ groupId ], $ exists , $ groupId );
348
+ $ this ->cleanupScheduleMismatches ();
340
349
341
350
/**
342
351
* save time schedules generation was ran with no expiration
@@ -469,13 +478,20 @@ public function saveSchedule($jobCode, $cronExpression, $timeInterval, $exists)
469
478
$ currentTime = $ this ->timezone ->scopeTimeStamp ();
470
479
$ timeAhead = $ currentTime + $ timeInterval ;
471
480
for ($ time = $ currentTime ; $ time < $ timeAhead ; $ time += self ::SECONDS_IN_MINUTE ) {
472
- $ timestamp = strftime ('%Y-%m-%d %H:%M:00 ' , $ time );
473
- if (!empty ($ exists [$ jobCode . '/ ' . $ timestamp ])) {
474
- // already scheduled
481
+ $ scheduledAt = strftime ('%Y-%m-%d %H:%M:00 ' , $ time );
482
+ $ alreadyScheduled = !empty ($ exists [$ jobCode . '/ ' . $ scheduledAt ]);
483
+ $ schedule = $ this ->generateSchedule ($ jobCode , $ cronExpression , $ time );
484
+ $ valid = $ schedule ->trySchedule ();
485
+ if (!$ valid ) {
486
+ if ($ alreadyScheduled ) {
487
+ if (!isset ($ this ->invalid [$ jobCode ])) {
488
+ $ this ->invalid [$ jobCode ] = [];
489
+ }
490
+ $ this ->invalid [$ jobCode ][] = $ scheduledAt ;
491
+ }
475
492
continue ;
476
493
}
477
- $ schedule = $ this ->generateSchedule ($ jobCode , $ cronExpression , $ time );
478
- if ($ schedule ->trySchedule ()) {
494
+ if (!$ alreadyScheduled ) {
479
495
// time matches cron expression
480
496
$ schedule ->save ();
481
497
}
@@ -516,6 +532,9 @@ public function getScheduleTimeInterval($groupId)
516
532
}
517
533
518
534
/**
535
+ * Clean up scheduled jobs that are disabled in the configuration
536
+ * This can happen when you turn off a cron job in the config and flush the cache
537
+ *
519
538
* @param $groupId
520
539
*/
521
540
public function cleanupDisabledJobs ($ groupId )
@@ -551,4 +570,24 @@ public function getCronExpression($jobConfig)
551
570
}
552
571
return $ cronExpression ;
553
572
}
573
+
574
+ /**
575
+ * Clean up scheduled jobs that do not match their cron expression anymore
576
+ * This can happen when you change the cron expression and flush the cache
577
+ *
578
+ * @return $this
579
+ */
580
+ public function cleanupScheduleMismatches ()
581
+ {
582
+ foreach ($ this ->invalid as $ jobCode => $ scheduledAtList ) {
583
+ /** @var \Magento\Cron\Model\ResourceModel\Schedule $scheduleResource */
584
+ $ scheduleResource = $ this ->scheduleFactory ->create ()->getResource ();
585
+ $ scheduleResource ->getConnection ()->delete ($ scheduleResource ->getMainTable (), [
586
+ 'status=? ' => Schedule::STATUS_PENDING ,
587
+ 'job_code=? ' => $ jobCode ,
588
+ 'scheduled_at in (?) ' => $ scheduledAtList ,
589
+ ]);
590
+ }
591
+ return $ this ;
592
+ }
554
593
}
0 commit comments