diff --git a/src/Symfony/Component/Scheduler/CHANGELOG.md b/src/Symfony/Component/Scheduler/CHANGELOG.md index e166a5d2f6b53..2fb6b75be694d 100644 --- a/src/Symfony/Component/Scheduler/CHANGELOG.md +++ b/src/Symfony/Component/Scheduler/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +7.2 +--- + + * Add capability to skip missed periodic tasks, only the last schedule will be called + 6.4 --- diff --git a/src/Symfony/Component/Scheduler/Generator/MessageGenerator.php b/src/Symfony/Component/Scheduler/Generator/MessageGenerator.php index 2c02f29344b89..e247748de023b 100644 --- a/src/Symfony/Component/Scheduler/Generator/MessageGenerator.php +++ b/src/Symfony/Component/Scheduler/Generator/MessageGenerator.php @@ -74,7 +74,15 @@ public function getMessages(): \Generator $yield = false; } - if ($nextTime = $trigger->getNextRunDate($time)) { + $nextTime = $trigger->getNextRunDate($time); + + if ($this->schedule->shouldProcessOnlyLastMissedRun()) { + while ($nextTime < $this->clock->now()) { + $nextTime = $trigger->getNextRunDate($nextTime); + } + } + + if ($nextTime) { $heap->insert([$nextTime, $index, $recurringMessage]); } diff --git a/src/Symfony/Component/Scheduler/Schedule.php b/src/Symfony/Component/Scheduler/Schedule.php index c23bfb9e0716a..1da3db35aad1f 100644 --- a/src/Symfony/Component/Scheduler/Schedule.php +++ b/src/Symfony/Component/Scheduler/Schedule.php @@ -31,6 +31,7 @@ public function __construct( private ?LockInterface $lock = null; private ?CacheInterface $state = null; private bool $shouldRestart = false; + private bool $onlyLastMissed = false; public function with(RecurringMessage $message, RecurringMessage ...$messages): static { @@ -123,6 +124,21 @@ public function getState(): ?CacheInterface return $this->state; } + /** + * @return $this + */ + public function processOnlyLastMissedRun(bool $onlyLastMissed): static + { + $this->onlyLastMissed = $onlyLastMissed; + + return $this; + } + + public function shouldProcessOnlyLastMissedRun(): bool + { + return $this->onlyLastMissed; + } + /** * @return array */ diff --git a/src/Symfony/Component/Scheduler/Tests/Generator/MessageGeneratorTest.php b/src/Symfony/Component/Scheduler/Tests/Generator/MessageGeneratorTest.php index 9f132108ad2da..43d966c4ffcf7 100644 --- a/src/Symfony/Component/Scheduler/Tests/Generator/MessageGeneratorTest.php +++ b/src/Symfony/Component/Scheduler/Tests/Generator/MessageGeneratorTest.php @@ -204,6 +204,67 @@ public function testCheckpointSavedInBrokenLoop() $this->assertEquals(self::makeDateTime('22:13:00'), $checkpoint->time()); } + public function testCheckpointSavedInBigBrokenLoop() + { + $clock = new MockClock(self::makeDateTime('22:15:00')); + + $message = RecurringMessage::every('1 minute', (object) ['id' => 'message']); + $schedule = (new Schedule())->add($message); + + $cache = new ArrayAdapter(); + $schedule->stateful($cache); + $checkpoint = new Checkpoint('dummy', cache: $cache); + + $scheduler = new MessageGenerator($schedule, 'dummy', clock: $clock, checkpoint: $checkpoint); + + // Warmup. The first run is always returns nothing. + $this->assertSame([], iterator_to_array($scheduler->getMessages(), false)); + $this->assertEquals(self::makeDateTime('22:15:00'), $checkpoint->time()); + + $clock->sleep(60 + 10); // 22:16:10 + + $this->assertCount(1, iterator_to_array($scheduler->getMessages(), false)); + + $clock->sleep(2 * 60); // 22:18:10 + + $this->assertCount(2, iterator_to_array($scheduler->getMessages(), false)); + + $clock->sleep(5 * 60); // 22:23:10 + + $this->assertCount(5, iterator_to_array($scheduler->getMessages(), false)); + + $this->assertEquals(self::makeDateTime('22:23:00'), $checkpoint->time()); + } + + public function testCheckpointSavedInBigBrokenLoopWithOnlyLastMissed() + { + $clock = new MockClock(self::makeDateTime('22:15:00')); + + $message = RecurringMessage::every('1 minute', (object) ['id' => 'message']); + $schedule = (new Schedule())->add($message); + + $cache = new ArrayAdapter(); + $schedule->stateful($cache)->processOnlyLastMissedRun(true); + $checkpoint = new Checkpoint('dummy', cache: $cache); + + $scheduler = new MessageGenerator($schedule, 'dummy', clock: $clock, checkpoint: $checkpoint); + + // Warmup. The first run is always returns nothing. + $this->assertSame([], iterator_to_array($scheduler->getMessages(), false)); + $this->assertEquals(self::makeDateTime('22:15:00'), $clock->now()); + + $clock->sleep(60 + 10); // 22:16:10 + $this->assertCount(1, iterator_to_array($scheduler->getMessages(), false)); + + $clock->sleep(2 * 60); // 22:18:10 + $this->assertCount(1, iterator_to_array($scheduler->getMessages(), false)); + + $clock->sleep(5 * 60); // 22:23:10 + $this->assertCount(1, iterator_to_array($scheduler->getMessages(), false)); + + $this->assertEquals(self::makeDateTime('22:23:10'), $clock->now()); + } + public static function messagesProvider(): \Generator { $first = (object) ['id' => 'first']; pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy