summaryrefslogtreecommitdiffstats
path: root/library/Reporting/Scheduler.php
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-14 13:28:59 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-14 13:28:59 +0000
commit978a1651bac3faf5e91ddba327bf39aeb6a4cb63 (patch)
treef0d1fee61877df200ccfb1c0af58a39cd551fb46 /library/Reporting/Scheduler.php
parentInitial commit. (diff)
downloadicingaweb2-module-reporting-978a1651bac3faf5e91ddba327bf39aeb6a4cb63.tar.xz
icingaweb2-module-reporting-978a1651bac3faf5e91ddba327bf39aeb6a4cb63.zip
Adding upstream version 0.10.0.upstream/0.10.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'library/Reporting/Scheduler.php')
-rw-r--r--library/Reporting/Scheduler.php176
1 files changed, 176 insertions, 0 deletions
diff --git a/library/Reporting/Scheduler.php b/library/Reporting/Scheduler.php
new file mode 100644
index 0000000..1b8d9f6
--- /dev/null
+++ b/library/Reporting/Scheduler.php
@@ -0,0 +1,176 @@
+<?php
+// Icinga Reporting | (c) 2018 Icinga GmbH | GPLv2
+
+namespace Icinga\Module\Reporting;
+
+use Cron\CronExpression;
+use ipl\Sql\Connection;
+use ipl\Sql\Select;
+use React\EventLoop\Factory as Loop;
+
+function datetime_get_time_of_day(\DateTime $dateTime)
+{
+ $midnight = clone $dateTime;
+ $midnight->modify('midnight');
+
+ $diff = $midnight->diff($dateTime);
+
+ return $diff->h * 60 * 60 + $diff->i * 60 + $diff->s;
+}
+
+class Scheduler
+{
+ protected $db;
+
+ protected $loop;
+
+ /** @var array */
+ protected $schedules = [];
+
+ /** @var array */
+ protected $timers = [];
+
+ public function __construct(Connection $db)
+ {
+ $this->db = $db;
+ $this->loop = Loop::create();
+ }
+
+ public function run()
+ {
+ $updateTimers = function () use (&$updateTimers) {
+ $this->updateTimers();
+
+ $this->loop->addTimer(60, $updateTimers);
+ };
+
+ $this->loop->futureTick($updateTimers);
+
+ $this->loop->run();
+ }
+
+ protected function fetchSchedules()
+ {
+ $schedules = [];
+
+ $select = (new Select())
+ ->from('schedule')
+ ->columns('*');
+
+ foreach ($this->db->select($select) as $row) {
+ $schedule = (new Schedule())
+ ->setId((int) $row->id)
+ ->setReportId((int) $row->report_id)
+ ->setAction($row->action)
+ ->setConfig(\json_decode($row->config, true))
+ ->setStart((new \DateTime())->setTimestamp((int) $row->start / 1000))
+ ->setFrequency($row->frequency);
+
+ $schedules[$schedule->getChecksum()] = $schedule;
+ }
+
+ return $schedules;
+ }
+
+ protected function updateTimers()
+ {
+ $schedules = $this->fetchSchedules();
+
+ $remove = \array_diff_key($this->schedules, $schedules);
+
+ foreach ($remove as $schedule) {
+ printf("Removing job %s.\n", "Schedule {$schedule->getId()}");
+
+ $checksum = $schedule->getChecksum();
+
+ if (isset($this->timers[$checksum])) {
+ $this->loop->cancelTimer($this->timers[$checksum]);
+ unset($this->timers[$checksum]);
+ } else {
+ printf("Can't find timer for job %s.\n", $checksum);
+ }
+ }
+
+ $add = \array_diff_key($schedules, $this->schedules);
+
+ foreach ($add as $schedule) {
+ $this->add($schedule);
+ }
+
+ $this->schedules = $schedules;
+ }
+
+
+ protected function add(Schedule $schedule)
+ {
+ $name = "Schedule {$schedule->getId()}";
+ $frequency = $schedule->getFrequency();
+ $start = clone $schedule->getStart();
+ $callback = function () use ($schedule) {
+ $actionClass = $schedule->getAction();
+ /** @var ActionHook $action */
+ $action = new $actionClass;
+
+ $action->execute(
+ Report::fromDb($schedule->getReportId()),
+ $schedule->getConfig()
+ );
+ };
+
+ switch ($frequency) {
+ case 'minutely':
+ $modify = '+1 minute';
+ break;
+ case 'hourly':
+ $modify = '+1 hour';
+ break;
+ case 'daily':
+ $modify = '+1 day';
+ break;
+ case 'weekly':
+ $modify = '+1 week';
+ break;
+ case 'monthly':
+ $modify = '+1 month';
+ break;
+ default:
+ throw new \InvalidArgumentException('Invalid frequency.');
+ }
+
+ $now = new \DateTime();
+
+ if ($start < $now) {
+// printf("Scheduling job %s to run immediately.\n", $name);
+// $this->loop->futureTick($callback);
+
+ while ($start < $now) {
+ $start->modify($modify);
+ }
+ }
+
+ $next = clone $start;
+ $next->modify($modify);
+ $interval = $next->getTimestamp() - $start->getTimestamp();
+
+ $current = $start->getTimestamp() - $now->getTimestamp();
+
+ printf("Scheduling job %s to run at %s.\n", $name, $start->format('Y-m-d H:i:s'));
+
+ $loop = function () use (&$loop, $name, $callback, $interval, $schedule) {
+ $callback();
+
+ $nextRun = (new \DateTime())
+ ->add(new \DateInterval("PT{$interval}S"));
+
+ printf("Scheduling job %s to run at %s.\n", $name, $nextRun->format('Y-m-d H:i:s'));
+
+ $timer = $this->loop->addTimer($interval, $loop);
+
+ $this->timers[$schedule->getChecksum()] = $timer;
+ };
+
+ $timer = $this->loop->addTimer($current, $loop);
+
+ $this->timers[$schedule->getChecksum()] = $timer;
+ }
+}