1313
1414use Cron \CronExpression ;
1515use DateTimeImmutable ;
16+ use DateTimeInterface ;
1617use EdgeTelemetrics \EventCorrelation \Event ;
1718use EdgeTelemetrics \EventCorrelation \Rule ;
1819use EdgeTelemetrics \EventCorrelation \Scheduler ;
@@ -47,6 +48,11 @@ abstract class Cron extends Rule
4748 */
4849 private CronExpression $ cron ;
4950
51+ /**
52+ * @var ?DateTimeInterface $cronLastRun Last time cron was executed
53+ */
54+ private ?DateTimeInterface $ cronLastRun = null ;
55+
5056 public function __construct ()
5157 {
5258 parent ::__construct ();
@@ -69,6 +75,7 @@ public function handle(Event $event) : int
6975 //Don't track the initialising event directly in the consumed events to allow processing of the static::EVENTS array correctly
7076 $ this ->initEvent = $ event ;
7177 $ this ->consumedEvents = [];
78+ $ this ->updateTimeout (); //Call this here now that we have initialised initEvent
7279 }
7380 if ($ event ->event === Scheduler::CONTROL_MSG_STOP ) {
7481 $ this ->isTimedOut = true ;
@@ -154,26 +161,38 @@ public function fire(): void
154161
155162 /**
156163 * @return void
157- * @throws Exception
158164 */
159165 public function updateTimeout () : void
160166 {
167+ /** @psalm-suppress RedundantPropertyInitializationCheck */
168+ if (!isset ($ this ->initEvent )) {
169+ //handle() will call updateTimeout prior to initEvent being set. Return early here
170+ $ this ->timeout = null ;
171+ return ;
172+ }
161173 /** @psalm-suppress TypeDoesNotContainType */
162174 if (!isset ($ this ->cron ) || $ this ->complete ()) {
163175 $ this ->timeout = null ;
164176 } else {
165177 if (static ::$ eventstream_live ) {
166178 $ currentTime = 'now ' ;
167179 } else {
180+ $ times = array_filter ([$ this ->getLastEvent ()?->datetime, $ this ->initEvent , $ this ->cronLastRun ]);
168181 /** @var DateTimeImmutable $currentTime */
169- $ currentTime = ($ this ->getLastEvent () ?? $ this ->initEvent )->datetime ;
182+ $ currentTime = max ($ times );
183+ }
184+ try {
185+ $ this ->timeout = DateTimeImmutable::createFromMutable ($ this ->cron ->getNextRunDate ($ currentTime , 0 , false , static ::TIMEZONE ));
186+ } catch (Exception ) {
187+ //Cron is invalid
188+ $ this ->timeout = null ;
170189 }
171- $ this ->timeout = DateTimeImmutable::createFromMutable ($ this ->cron ->getNextRunDate ($ currentTime , 0 , false , static ::TIMEZONE ));
172190 }
173191 }
174192
175193 //Called when the timeout is reached
176194 public function alarm () : void {
195+ $ this ->cronLastRun = $ this ->getTimeout ();
177196 $ this ->onSchedule ();
178197 if (!$ this ->complete () && !$ this ->isTimedOut ()) {
179198 $ this ->updateTimeout ();
0 commit comments