site-accueil-insa/matomo/core/Scheduler/Timetable.php

240 lines
6.1 KiB
PHP

<?php
/**
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Scheduler;
use Piwik\Common;
use Piwik\Option;
use Piwik\Date;
/**
* This data structure holds the scheduled times for each active scheduled task.
*/
class Timetable
{
const TIMETABLE_OPTION_STRING = "TaskScheduler.timetable";
const RETRY_OPTION_STRING = "TaskScheduler.retryList";
private $timetable;
private $retryList;
public function __construct()
{
$this->readFromOption();
}
public function getTimetable()
{
return $this->timetable;
}
public function setTimetable($timetable)
{
$this->timetable = $timetable;
}
public function setRetryList($retryList)
{
$this->retryList = $retryList;
}
/**
* @param Task[] $activeTasks
*/
public function removeInactiveTasks($activeTasks)
{
$activeTaskNames = array();
foreach ($activeTasks as $task) {
$activeTaskNames[] = $task->getName();
}
foreach (array_keys($this->timetable) as $taskName) {
if (!in_array($taskName, $activeTaskNames)) {
unset($this->timetable[$taskName]);
}
}
$this->save();
}
public function getScheduledTaskNames()
{
return array_keys($this->timetable);
}
public function getScheduledTaskTime($taskName)
{
return isset($this->timetable[$taskName]) ? Date::factory($this->timetable[$taskName]) : false;
}
/**
* Checks if the task should be executed
*
* Task has to be executed if :
* - the task has already been scheduled once and the current system time is greater than the scheduled time.
* - execution is forced, see $forceTaskExecution
*
* @param string $taskName
*
* @return boolean
*/
public function shouldExecuteTask($taskName)
{
$forceTaskExecution = (defined('DEBUG_FORCE_SCHEDULED_TASKS') && DEBUG_FORCE_SCHEDULED_TASKS);
if ($forceTaskExecution) {
return true;
}
return $this->taskHasBeenScheduledOnce($taskName) && time() >= $this->timetable[$taskName];
}
/**
* Checks if a task should be rescheduled
*
* Task has to be rescheduled if :
* - the task has to be executed
* - the task has never been scheduled before
*
* @param string $taskName
*
* @return boolean
*/
public function taskShouldBeRescheduled($taskName)
{
return !$this->taskHasBeenScheduledOnce($taskName) || $this->shouldExecuteTask($taskName);
}
public function rescheduleTask(Task $task)
{
$rescheduledTime = $task->getRescheduledTime();
// update the scheduled time
$this->timetable[$task->getName()] = $rescheduledTime;
$this->save();
return Date::factory($rescheduledTime);
}
public function rescheduleTaskAndRunTomorrow(Task $task)
{
$tomorrow = Date::factory('tomorrow');
// update the scheduled time
$this->timetable[$task->getName()] = $tomorrow->getTimestamp();
$this->save();
return $tomorrow;
}
public function rescheduleTaskAndRunInOneHour(Task $task)
{
$oneHourFromNow = Date::factory('now')->addHour(1);
// update the scheduled time
$this->timetable[$task->getName()] = $oneHourFromNow->getTimestamp();
$this->save();
return $oneHourFromNow;
}
public function save()
{
Option::set(self::TIMETABLE_OPTION_STRING, serialize($this->timetable));
}
public function getScheduledTimeForMethod($className, $methodName, $methodParameter = null)
{
$taskName = Task::getTaskName($className, $methodName, $methodParameter);
return $this->taskHasBeenScheduledOnce($taskName) ? $this->timetable[$taskName] : false;
}
public function taskHasBeenScheduledOnce($taskName)
{
return isset($this->timetable[$taskName]);
}
public function readFromOption()
{
Option::clearCachedOption(self::TIMETABLE_OPTION_STRING);
$optionData = Option::get(self::TIMETABLE_OPTION_STRING);
$unserializedTimetable = Common::safe_unserialize($optionData);
$this->timetable = $unserializedTimetable === false ? array() : $unserializedTimetable;
}
/**
* Read the retry list option from the database
*
* @throws \Throwable
*/
private function readRetryList()
{
Option::clearCachedOption(self::RETRY_OPTION_STRING);
$retryData = Option::get(self::RETRY_OPTION_STRING);
$unserializedRetryList = Common::safe_unserialize($retryData);
$this->retryList = $unserializedRetryList === false ? array() : $unserializedRetryList;
}
/**
* Save the retry list option to the database
*/
public function saveRetryList()
{
Option::set(self::RETRY_OPTION_STRING, serialize($this->retryList));
}
/**
* Remove a task from the retry list
*
* @param string $taskName
*/
public function clearRetryCount(string $taskName)
{
if (isset($this->retryList[$taskName])) {
unset($this->retryList[$taskName]);
$this->saveRetryList();
}
}
/**
* Increment the retry counter for a task
*
* @param string $taskName
*/
public function incrementRetryCount(string $taskName)
{
$this->readRetryList();
if (!isset($this->retryList[$taskName])) {
$this->retryList[$taskName] = 0;
}
$this->retryList[$taskName]++;
$this->saveRetryList();
}
/**
* Return the current number of retries for a task
*
* @param string $taskName
*
* @return int
*/
public function getRetryCount(string $taskName) : int
{
$this->readRetryList();
// Ignore excessive retry counts, workaround for SchedulerTest mock
if (!isset($this->retryList[$taskName]) || $this->retryList[$taskName] > 10000) {
return 0;
}
return $this->retryList[$taskName];
}
}