### there are no events scheduled?
my @events = $self->list_events or return;
- my $now = DateTime->now( time_zone => $tz );
+ my $now = DateTime->now( time_zone => $tz )->epoch;
### list of pending events
my @pending;
### we're due according to our cron-entry...
if( $event->set ) {
### is the next run time now, or even before now?
- push @pending, $event if $event->next_run_as_dt <= $now;
+ push @pending, $event if $event->next_run <= $now;
}
}
=cut
-sub next_run_as_dt {
- my $self = shift;
-
- if( $self->set ) {
- my $dt = DateTime->from_epoch(
- epoch => $self->_last_check_time,
- time_zone => $Base->_config('time_zone'),
- );
- return $self->set->next( $dt );
- }
- return;
+{ my %cache = ();
+
+ sub next_run_as_dt {
+ my $self = shift;
+
+ ### the time for the next run is EITHER based on the last_run time
+ ### ie, if the last run time is 61 seconds ago, and it's a per minute
+ ### schedule, the 'next run' should return a time of 1 second ago.
+ ### similarly, if the last run time is 2 hours ago, the 'next run'
+ ### should return a time of 1h59mins ago, which again means it's due.
+ ### The 'last_run' may be 0 (or better yet, undef), in that case,
+ ### we assume the last run time was NOW. The problem is that if we
+ ### keep asking the 'next_run' time on subsequent requests, it will
+ ### always be based on 'NOW' + 1 minute (for events running every
+ ### minute), which will always be in the future. Hence we cache
+ ### the answer the first time 'last_run' returns false (ie, never
+ ### run) and use that answer as a fallback, meaning that if we come
+ ### back later (say, 65 seconds later), the 'next run' will be based
+ ### on NOW - 65 + 1 minute, which is 5 seconds ago, and hence the
+ ### event will trigger...
+ my $epoch = $self->last_run ||
+ $cache{$self} ||
+ do { $cache{$self} = time };
+
+ if( $self->set ) {
+ my $dt = DateTime->from_epoch(
+ epoch => $epoch,
+ time_zone => $Base->_config('time_zone'),
+ );
+ return $self->set->next( $dt );
+ }
+ return;
+ }
}
=head2 $bool = $event->run( ... )