Teknik is a suite of services with attractive and functional interfaces. https://www.teknik.io/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TaskScheduler.php 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. <?php
  2. /**
  3. * Piwik - free/libre analytics platform
  4. *
  5. * @link http://piwik.org
  6. * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
  7. *
  8. */
  9. namespace Piwik;
  10. use Exception;
  11. use Piwik\Plugin\Manager as PluginManager;
  12. // When set to true, all scheduled tasks will be triggered in all requests (careful!)
  13. define('DEBUG_FORCE_SCHEDULED_TASKS', false);
  14. /**
  15. * Manages scheduled task execution.
  16. *
  17. * A scheduled task is a callback that should be executed every so often (such as daily,
  18. * weekly, monthly, etc.). They are registered with **TaskScheduler** through the
  19. * {@hook TaskScheduler.getScheduledTasks} event.
  20. *
  21. * Tasks are executed when the cron core:archive command is executed.
  22. *
  23. * ### Examples
  24. *
  25. * **Scheduling a task**
  26. *
  27. * // event handler for TaskScheduler.getScheduledTasks event
  28. * public function getScheduledTasks(&$tasks)
  29. * {
  30. * $tasks[] = new ScheduledTask(
  31. * 'Piwik\Plugins\CorePluginsAdmin\MarketplaceApiClient',
  32. * 'clearAllCacheEntries',
  33. * null,
  34. * ScheduledTime::factory('daily'),
  35. * ScheduledTask::LOWEST_PRIORITY
  36. * );
  37. * }
  38. *
  39. * **Executing all pending tasks**
  40. *
  41. * $results = TaskScheduler::runTasks();
  42. * $task1Result = $results[0];
  43. * $task1Name = $task1Result['task'];
  44. * $task1Output = $task1Result['output'];
  45. *
  46. * echo "Executed task '$task1Name'. Task output:\n$task1Output";
  47. *
  48. * @method static \Piwik\TaskScheduler getInstance()
  49. */
  50. class TaskScheduler extends Singleton
  51. {
  52. const GET_TASKS_EVENT = 'TaskScheduler.getScheduledTasks';
  53. private $isRunning = false;
  54. private $timetable = null;
  55. public function __construct()
  56. {
  57. $this->timetable = new ScheduledTaskTimetable();
  58. }
  59. /**
  60. * Executes tasks that are scheduled to run, then reschedules them.
  61. *
  62. * @return array An array describing the results of scheduled task execution. Each element
  63. * in the array will have the following format:
  64. *
  65. * ```
  66. * array(
  67. * 'task' => 'task name',
  68. * 'output' => '... task output ...'
  69. * )
  70. * ```
  71. */
  72. public static function runTasks()
  73. {
  74. return self::getInstance()->doRunTasks();
  75. }
  76. // for backwards compatibility
  77. private function collectTasksRegisteredViaEvent()
  78. {
  79. $tasks = array();
  80. /**
  81. * @ignore
  82. * @deprecated
  83. */
  84. Piwik::postEvent(self::GET_TASKS_EVENT, array(&$tasks));
  85. return $tasks;
  86. }
  87. private function getScheduledTasks()
  88. {
  89. /** @var \Piwik\ScheduledTask[] $tasks */
  90. $tasks = $this->collectTasksRegisteredViaEvent();
  91. /** @var \Piwik\Plugin\Tasks[] $pluginTasks */
  92. $pluginTasks = PluginManager::getInstance()->findComponents('Tasks', 'Piwik\\Plugin\\Tasks');
  93. foreach ($pluginTasks as $pluginTask) {
  94. $pluginTask->schedule();
  95. foreach ($pluginTask->getScheduledTasks() as $task) {
  96. $tasks[] = $task;
  97. }
  98. }
  99. return $tasks;
  100. }
  101. private function doRunTasks()
  102. {
  103. $tasks = $this->getScheduledTasks();
  104. // remove from timetable tasks that are not active anymore
  105. $this->timetable->removeInactiveTasks($tasks);
  106. // for every priority level, starting with the highest and concluding with the lowest
  107. $executionResults = array();
  108. for ($priority = ScheduledTask::HIGHEST_PRIORITY;
  109. $priority <= ScheduledTask::LOWEST_PRIORITY;
  110. ++$priority) {
  111. // loop through each task
  112. foreach ($tasks as $task) {
  113. // if the task does not have the current priority level, don't execute it yet
  114. if ($task->getPriority() != $priority) {
  115. continue;
  116. }
  117. $taskName = $task->getName();
  118. $shouldExecuteTask = $this->timetable->shouldExecuteTask($taskName);
  119. if ($this->timetable->taskShouldBeRescheduled($taskName)) {
  120. $this->timetable->rescheduleTask($task);
  121. }
  122. if ($shouldExecuteTask) {
  123. $this->isRunning = true;
  124. $message = self::executeTask($task);
  125. $this->isRunning = false;
  126. $executionResults[] = array('task' => $taskName, 'output' => $message);
  127. }
  128. }
  129. }
  130. return $executionResults;
  131. }
  132. /**
  133. * Determines a task's scheduled time and persists it, overwriting the previous scheduled time.
  134. *
  135. * Call this method if your task's scheduled time has changed due to, for example, an option that
  136. * was changed.
  137. *
  138. * @param ScheduledTask $task Describes the scheduled task being rescheduled.
  139. * @api
  140. */
  141. public static function rescheduleTask(ScheduledTask $task)
  142. {
  143. self::getInstance()->timetable->rescheduleTask($task);
  144. }
  145. /**
  146. * Returns true if the TaskScheduler is currently running a scheduled task.
  147. *
  148. * @return bool
  149. */
  150. public static function isTaskBeingExecuted()
  151. {
  152. return self::getInstance()->isRunning;
  153. }
  154. /**
  155. * Return the next scheduled time given the class and method names of a scheduled task.
  156. *
  157. * @param string $className The name of the class that contains the scheduled task method.
  158. * @param string $methodName The name of the scheduled task method.
  159. * @param string|null $methodParameter Optional method parameter.
  160. * @return mixed int|bool The time in miliseconds when the scheduled task will be executed
  161. * next or false if it is not scheduled to run.
  162. */
  163. public static function getScheduledTimeForMethod($className, $methodName, $methodParameter = null)
  164. {
  165. return self::getInstance()->timetable->getScheduledTimeForMethod($className, $methodName, $methodParameter);
  166. }
  167. /**
  168. * Executes the given taks
  169. *
  170. * @param ScheduledTask $task
  171. * @return string
  172. */
  173. private static function executeTask($task)
  174. {
  175. try {
  176. $timer = new Timer();
  177. call_user_func(array($task->getObjectInstance(), $task->getMethodName()), $task->getMethodParameter());
  178. $message = $timer->__toString();
  179. } catch (Exception $e) {
  180. $message = 'ERROR: ' . $e->getMessage();
  181. }
  182. return $message;
  183. }
  184. }