Skip to content

Commit 1add384

Browse files
Jeroenyfabpot
authored andcommitted
[Scheduler] Allow modifying the schedule at runtime and recalculate heap
1 parent 11adee9 commit 1add384

File tree

4 files changed

+121
-3
lines changed

4 files changed

+121
-3
lines changed

src/Symfony/Component/Scheduler/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ CHANGELOG
1010
* Add `AbstractTriggerDecorator`
1111
* Make `ScheduledStamp` "send-able"
1212
* Add `ScheduledStamp` to `RedispatchMessage`
13+
* Allow modifying the Schedule at runtime
1314

1415
6.3
1516
---

src/Symfony/Component/Scheduler/Generator/MessageGenerator.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
final class MessageGenerator implements MessageGeneratorInterface
2121
{
22-
private Schedule $schedule;
22+
private ?Schedule $schedule = null;
2323
private TriggerHeap $triggerHeap;
2424
private ?\DateTimeImmutable $waitUntil;
2525

@@ -36,6 +36,12 @@ public function getMessages(): \Generator
3636
{
3737
$checkpoint = $this->checkpoint();
3838

39+
if ($this->schedule?->shouldRestart()) {
40+
unset($this->triggerHeap);
41+
$this->waitUntil = new \DateTimeImmutable('@0');
42+
$this->schedule->setRestart(false);
43+
}
44+
3945
if (!$this->waitUntil
4046
|| $this->waitUntil > ($now = $this->clock->now())
4147
|| !$checkpoint->acquire($now)

src/Symfony/Component/Scheduler/Schedule.php

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,55 @@ final class Schedule implements ScheduleProviderInterface
2121
private array $messages = [];
2222
private ?LockInterface $lock = null;
2323
private ?CacheInterface $state = null;
24+
private bool $shouldRestart = false;
25+
26+
public static function with(RecurringMessage $message, RecurringMessage ...$messages): static
27+
{
28+
return static::doAdd(new self(), $message, ...$messages);
29+
}
2430

2531
/**
2632
* @return $this
2733
*/
2834
public function add(RecurringMessage $message, RecurringMessage ...$messages): static
35+
{
36+
$this->setRestart(true);
37+
38+
return static::doAdd($this, $message, ...$messages);
39+
}
40+
41+
private static function doAdd(self $schedule, RecurringMessage $message, RecurringMessage ...$messages): static
2942
{
3043
foreach ([$message, ...$messages] as $m) {
31-
if (isset($this->messages[$m->getId()])) {
44+
if (isset($schedule->messages[$m->getId()])) {
3245
throw new LogicException('Duplicated schedule message.');
3346
}
3447

35-
$this->messages[$m->getId()] = $m;
48+
$schedule->messages[$m->getId()] = $m;
3649
}
3750

51+
return $schedule;
52+
}
53+
54+
/**
55+
* @return $this
56+
*/
57+
public function remove(RecurringMessage $message): static
58+
{
59+
unset($this->messages[$message->getId()]);
60+
$this->setRestart(true);
61+
62+
return $this;
63+
}
64+
65+
/**
66+
* @return $this
67+
*/
68+
public function clear(): static
69+
{
70+
$this->messages = [];
71+
$this->setRestart(true);
72+
3873
return $this;
3974
}
4075

@@ -83,4 +118,14 @@ public function getSchedule(): static
83118
{
84119
return $this;
85120
}
121+
122+
public function shouldRestart(): bool
123+
{
124+
return $this->shouldRestart;
125+
}
126+
127+
public function setRestart(bool $shouldRestart): bool
128+
{
129+
return $this->shouldRestart = $shouldRestart;
130+
}
86131
}

src/Symfony/Component/Scheduler/Tests/Generator/MessageGeneratorTest.php

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,72 @@ public function getSchedule(): Schedule
9595
}
9696
}
9797

98+
public function testGetMessagesFromScheduleProviderWithRestart()
99+
{
100+
$first = (object) ['id' => 'first'];
101+
$startTime = '22:12:00';
102+
$runs = [
103+
'22:12:00' => [],
104+
'22:12:01' => [],
105+
'22:13:00' => [$first],
106+
'22:13:01' => [],
107+
];
108+
$schedule = [[$first, '22:13:00', '22:14:00']];
109+
110+
// for referencing
111+
$now = self::makeDateTime($startTime);
112+
113+
$clock = $this->createMock(ClockInterface::class);
114+
$clock->method('now')->willReturnReference($now);
115+
116+
foreach ($schedule as $i => $s) {
117+
if (\is_array($s)) {
118+
$schedule[$i] = $this->createMessage(...$s);
119+
}
120+
}
121+
122+
$scheduleProvider = new class($schedule) implements ScheduleProviderInterface {
123+
private Schedule $schedule;
124+
125+
public function __construct(array $schedule)
126+
{
127+
$this->schedule = Schedule::with(...$schedule);
128+
$this->schedule->stateful(new ArrayAdapter());
129+
}
130+
131+
public function getSchedule(): Schedule
132+
{
133+
return $this->schedule;
134+
}
135+
136+
public function add(RecurringMessage $message): self
137+
{
138+
$this->schedule->add($message);
139+
140+
return $this;
141+
}
142+
};
143+
144+
$scheduler = new MessageGenerator($scheduleProvider, 'dummy', $clock);
145+
146+
// Warmup. The first run always returns nothing.
147+
$this->assertSame([], iterator_to_array($scheduler->getMessages(), false));
148+
149+
$toAdd = (object) ['id' => 'added-after-start'];
150+
151+
foreach ($runs as $time => $expected) {
152+
$now = self::makeDateTime($time);
153+
$this->assertSame($expected, iterator_to_array($scheduler->getMessages(), false));
154+
}
155+
156+
$scheduleProvider->add($this->createMessage($toAdd, '22:13:10', '22:13:11'));
157+
158+
$this->assertSame([], iterator_to_array($scheduler->getMessages(), false));
159+
160+
$now = self::makeDateTime('22:13:10');
161+
$this->assertSame([$toAdd], iterator_to_array($scheduler->getMessages(), false));
162+
}
163+
98164
public function testYieldedContext()
99165
{
100166
// for referencing

0 commit comments

Comments
 (0)
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