PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 4.3.0
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v4.3.0
5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / app / core / Scheduler / Scheduler.php
matomo / app / core / Scheduler Last commit date
Schedule 5 years ago Scheduler.php 5 years ago Task.php 5 years ago TaskLoader.php 5 years ago Timetable.php 5 years ago
Scheduler.php
291 lines
1 <?php
2 /**
3 * Matomo - free/libre analytics platform
4 *
5 * @link https://matomo.org
6 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
7 */
8
9 namespace Piwik\Scheduler;
10
11 use Exception;
12 use Piwik\Piwik;
13 use Piwik\Timer;
14 use Psr\Log\LoggerInterface;
15
16 /**
17 * Schedules task execution.
18 *
19 * A scheduled task is a callback that should be executed every so often (such as daily,
20 * weekly, monthly, etc.). They are registered by extending {@link \Piwik\Plugin\Tasks}.
21 *
22 * Tasks are executed when the `core:archive` command is executed.
23 *
24 * ### Examples
25 *
26 * **Scheduling a task**
27 *
28 * class Tasks extends \Piwik\Plugin\Tasks
29 * {
30 * public function schedule()
31 * {
32 * $this->hourly('myTask'); // myTask() will be executed once every hour
33 * }
34 * public function myTask()
35 * {
36 * // do something
37 * }
38 * }
39 *
40 * **Executing all pending tasks**
41 *
42 * $results = $scheduler->run();
43 * $task1Result = $results[0];
44 * $task1Name = $task1Result['task'];
45 * $task1Output = $task1Result['output'];
46 *
47 * echo "Executed task '$task1Name'. Task output:\n$task1Output";
48 */
49 class Scheduler
50 {
51 /**
52 * Is the scheduler running any task.
53 * @var bool
54 */
55 private $isRunningTask = false;
56
57 /**
58 * @var Timetable
59 */
60 private $timetable;
61
62 /**
63 * @var TaskLoader
64 */
65 private $loader;
66
67 /**
68 * @var LoggerInterface
69 */
70 private $logger;
71
72 public function __construct(TaskLoader $loader, LoggerInterface $logger)
73 {
74 $this->timetable = new Timetable();
75 $this->loader = $loader;
76 $this->logger = $logger;
77 }
78
79 /**
80 * Executes tasks that are scheduled to run, then reschedules them.
81 *
82 * @return array An array describing the results of scheduled task execution. Each element
83 * in the array will have the following format:
84 *
85 * ```
86 * array(
87 * 'task' => 'task name',
88 * 'output' => '... task output ...'
89 * )
90 * ```
91 */
92 public function run()
93 {
94 $tasks = $this->loader->loadTasks();
95
96 $this->logger->debug('{count} scheduled tasks loaded', array('count' => count($tasks)));
97
98 // remove from timetable tasks that are not active anymore
99 $this->timetable->removeInactiveTasks($tasks);
100
101 $this->logger->info("Starting Scheduled tasks... ");
102
103 // for every priority level, starting with the highest and concluding with the lowest
104 $executionResults = array();
105 for ($priority = Task::HIGHEST_PRIORITY; $priority <= Task::LOWEST_PRIORITY; ++$priority) {
106 $this->logger->debug("Executing tasks with priority {priority}:", array('priority' => $priority));
107
108 // loop through each task
109 foreach ($tasks as $task) {
110 // if the task does not have the current priority level, don't execute it yet
111 if ($task->getPriority() != $priority) {
112 continue;
113 }
114
115 $this->timetable->readFromOption();
116
117 $taskName = $task->getName();
118 $shouldExecuteTask = $this->timetable->shouldExecuteTask($taskName);
119
120 if ($this->timetable->taskShouldBeRescheduled($taskName)) {
121 $rescheduledDate = $this->timetable->rescheduleTask($task);
122
123 $this->logger->debug("Task {task} is scheduled to run again for {date}.", array('task' => $taskName, 'date' => $rescheduledDate));
124 }
125
126 /**
127 * Triggered before a task is executed.
128 *
129 * A plugin can listen to it and modify whether a specific task should be executed or not. This way
130 * you can force certain tasks to be executed more often or for example to be never executed.
131 *
132 * @param bool &$shouldExecuteTask Decides whether the task will be executed.
133 * @param Task $task The task that is about to be executed.
134 */
135 Piwik::postEvent('ScheduledTasks.shouldExecuteTask', array(&$shouldExecuteTask, $task));
136
137 if ($shouldExecuteTask) {
138 $message = $this->executeTask($task);
139
140 $executionResults[] = array('task' => $taskName, 'output' => $message);
141 }
142 }
143 }
144
145 $this->logger->info("done");
146
147 return $executionResults;
148 }
149
150 /**
151 * Run a specific task now. Will ignore the schedule completely.
152 *
153 * @param string $taskName
154 * @return string Task output.
155 */
156 public function runTaskNow($taskName)
157 {
158 $tasks = $this->loader->loadTasks();
159
160 foreach ($tasks as $task) {
161 if ($task->getName() === $taskName) {
162 return $this->executeTask($task);
163 }
164 }
165
166 throw new \InvalidArgumentException('Task ' . $taskName . ' not found');
167 }
168
169 /**
170 * Determines a task's scheduled time and persists it, overwriting the previous scheduled time.
171 *
172 * Call this method if your task's scheduled time has changed due to, for example, an option that
173 * was changed.
174 *
175 * @param Task $task Describes the scheduled task being rescheduled.
176 * @api
177 */
178 public function rescheduleTask(Task $task)
179 {
180 $this->logger->debug('Rescheduling task {task}', array('task' => $task->getName()));
181
182 $this->timetable->rescheduleTask($task);
183 }
184
185 /**
186 * Determines a task's scheduled time and persists it, overwriting the previous scheduled time.
187 *
188 * Call this method if your task's scheduled time has changed due to, for example, an option that
189 * was changed.
190 *
191 * The task will be run the first time tomorrow.
192 *
193 * @param Task $task Describes the scheduled task being rescheduled.
194 * @api
195 */
196 public function rescheduleTaskAndRunTomorrow(Task $task)
197 {
198 $this->logger->debug('Rescheduling task and setting first run for tomorrow {task}', array('task' => $task->getName()));
199
200 $this->timetable->rescheduleTaskAndRunTomorrow($task);
201 }
202
203 /**
204 * Returns true if the scheduler is currently running a task.
205 *
206 * @return bool
207 */
208 public function isRunningTask()
209 {
210 return $this->isRunningTask;
211 }
212
213 /**
214 * Return the next scheduled time given the class and method names of a scheduled task.
215 *
216 * @param string $className The name of the class that contains the scheduled task method.
217 * @param string $methodName The name of the scheduled task method.
218 * @param string|null $methodParameter Optional method parameter.
219 * @return mixed int|bool The time in milliseconds when the scheduled task will be executed
220 * next or false if it is not scheduled to run.
221 */
222 public function getScheduledTimeForMethod($className, $methodName, $methodParameter = null)
223 {
224 return $this->timetable->getScheduledTimeForMethod($className, $methodName, $methodParameter);
225 }
226
227 /**
228 * Returns the list of the task names.
229 *
230 * @return string[]
231 */
232 public function getTaskList()
233 {
234 $tasks = $this->loader->loadTasks();
235
236 return array_map(function (Task $task) {
237 return $task->getName();
238 }, $tasks);
239 }
240
241 /**
242 * Executes the given task
243 *
244 * @param Task $task
245 * @return string
246 */
247 private function executeTask($task)
248 {
249 $this->logger->info("Scheduler: executing task {taskName}...", array(
250 'taskName' => $task->getName(),
251 ));
252
253 $this->isRunningTask = true;
254
255 $timer = new Timer();
256
257 /**
258 * Triggered directly before a scheduled task is executed
259 *
260 * @param Task $task The task that is about to be executed
261 */
262 Piwik::postEvent('ScheduledTasks.execute', array(&$task));
263
264 try {
265 $callable = array($task->getObjectInstance(), $task->getMethodName());
266 call_user_func($callable, $task->getMethodParameter());
267 $message = $timer->__toString();
268 } catch (Exception $e) {
269 $message = 'ERROR: ' . $e->getMessage();
270 }
271
272 $this->isRunningTask = false;
273
274 /**
275 * Triggered after a scheduled task is successfully executed.
276 *
277 * You can use the event to execute for example another task whenever a specific task is executed or to clean up
278 * certain resources.
279 *
280 * @param Task $task The task that was just executed
281 */
282 Piwik::postEvent('ScheduledTasks.execute.end', array(&$task));
283
284 $this->logger->info("Scheduler: finished. {timeElapsed}", array(
285 'timeElapsed' => $timer,
286 ));
287
288 return $message;
289 }
290 }
291