public function enqueue()
{
$queue = new ArrayObject([]);
$db = \Scalr::getDb();
// get active tasks: first run (condition and last_start_time is null), others (condition and last_start_time + interval * 0.9 < now())
$taskList = $db->GetAll("\n SELECT *\n FROM scheduler\n WHERE `status` = ?\n AND (`start_time` IS NULL OR CONVERT_TZ(`start_time`,'SYSTEM',`timezone`) <= CONVERT_TZ(NOW(),'SYSTEM',`timezone`))\n AND (`last_start_time` IS NULL OR\n `last_start_time` IS NOT NULL AND `start_time` IS NULL AND (CONVERT_TZ(last_start_time + INTERVAL restart_every MINUTE, 'SYSTEM', `timezone`) < CONVERT_TZ(NOW(),'SYSTEM',`timezone`)) OR\n `last_start_time` IS NOT NULL AND `start_time` IS NOT NULL AND (CONVERT_TZ(last_start_time + INTERVAL (restart_every * 0.9) MINUTE, 'SYSTEM', `timezone`) < CONVERT_TZ(NOW(),'SYSTEM',`timezone`))\n )\n ORDER BY IF (last_start_time, last_start_time, start_time) ASC\n ", [Scalr_SchedulerTask::STATUS_ACTIVE]);
if (!$taskList) {
$this->getLogger()->info("There are no tasks to execute in scheduler table.");
return $queue;
}
$this->getLogger()->info("Found %d tasks", count($taskList));
foreach ($taskList as $task) {
try {
// check account status (active or inactive)
if (Scalr_Account::init()->loadById($task['account_id'])->status != Scalr_Account::STATUS_ACTIVE) {
continue;
}
} catch (Exception $e) {
$this->getLogger()->info("Scheduler task #%s could not start: %s", $task['id'], $e->getMessage());
}
if ($task['last_start_time'] && $task['start_time']) {
// try to auto-align time to start time
$startTime = new DateTime($task['start_time']);
$startTime->setTimezone(new DateTimeZone($task['timezone']));
$currentTime = new DateTime('now', new DateTimeZone($task['timezone']));
$offset = $startTime->getOffset() - $currentTime->getOffset();
$num = ($currentTime->getTimestamp() - $startTime->getTimestamp() - $offset) / ($task['restart_every'] * 60);
$numFloor = floor($num);
// we check tasks which are longer than hour
if ($task['restart_every'] > 55) {
// check how much intervals were missed
$lastStartTime = new DateTime($task['last_start_time']);
$lastStartTime->setTimezone(new DateTimeZone($task['timezone']));
if (($currentTime->getTimestamp() - $lastStartTime->getTimestamp() - ($lastStartTime->getOffset() - $currentTime->getOffset())) / ($task['restart_every'] * 60) > 2) {
// we missed one extra (or more) interval, so let's check if currentTime is synchronized with startTime
if ($num - $numFloor > 0.1) {
$this->getLogger()->debug(sprintf('Delay task (missed interval): %s, num: %f', $task['name'], $num));
continue;
}
}
}
// because of timezone's transitions
// num should be less than 0.5 (because of interval * 0.9 in SQL query)
if ($numFloor != round($num, 0, PHP_ROUND_HALF_UP)) {
$this->getLogger()->debug(sprintf('Delay task (interval): %s, Offset: %d, num: %f, floor: %f, round: %f', $task['name'], $offset, $num, floor($num), round($num, 0, PHP_ROUND_HALF_UP)));
continue;
}
}
$this->log('DEBUG', "Adding task %s to queue", $task['id']);
$queue->append($task['id']);
}
return $queue;
}