PluginProbe ʕ •ᴥ•ʔ
MailPoet – Newsletters, Email Marketing, and Automation / 4.1.1
MailPoet – Newsletters, Email Marketing, and Automation v4.1.1
5.28.1 5.28.0 5.27.0 5.26.0 5.26.1 5.25.0 5.24.0 4.43.0 4.43.1 4.44.0 4.44.1 4.45.0 4.46.0 4.47.0 4.48.0 4.48.1 4.48.2 4.49.0 4.49.1 4.5.0 4.5.1 4.5.2 4.50.0 4.50.1 4.51.0 4.51.1 4.51.2 4.52.0 4.53.0 4.54.0 4.55.0 4.56.0 4.57.0 4.58.0 4.58.1 4.58.2 4.6.0 4.6.1 4.6.2 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 5.0.0 5.0.1 5.0.2 5.1.0 5.1.1 5.10.0 5.10.1 5.11.0 5.12.0 5.12.1 5.12.10 5.12.11 5.12.12 5.12.13 5.12.2 5.12.3 5.12.4 5.12.5 5.12.6 5.12.7 5.12.8 5.12.9 5.13.0 5.13.1 5.13.2 5.14.0 5.14.1 5.14.2 5.14.3 5.15.0 5.15.1 5.16.0 5.16.1 5.16.2 5.16.3 5.16.4 5.17.0 5.17.1 5.17.2 5.17.3 5.17.4 5.17.5 5.17.6 5.18.0 5.19.0 5.2.0 5.2.1 5.2.2 5.2.3 5.20.0 5.21.0 5.21.1 5.21.2 5.21.3 5.22.0 5.22.1 5.22.2 5.22.3 5.22.4 5.23.0 5.23.1 5.23.2 5.3.0 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.3.7 5.4.0 5.4.1 5.4.2 5.5.0 5.5.1 5.5.2 5.6.0 5.6.1 5.6.2 5.6.3 5.6.4 5.7.0 5.7.1 5.8.0 5.8.1 5.9.0 3.0.0-beta.15 3.7.1 3.0.0-beta.16 3.7.2 3.0.0-beta.17 3.7.3 3.0.0-beta.18 3.7.4 3.0.0-beta.19 3.7.5 3.0.0-beta.2 3.7.6 3.0.0-beta.20 3.7.8 3.0.0-beta.21 3.70.0 3.0.0-beta.22 3.71.0 3.0.0-beta.23 3.71.1 3.0.0-beta.23.1 3.71.2 3.0.0-beta.23.2 3.71.3 3.0.0-beta.24 3.72.0 3.0.0-beta.25 3.73.0 3.0.0-beta.26 3.73.1 3.0.0-beta.27 3.73.2 3.0.0-beta.28 3.74.0 3.0.0-beta.29 3.74.1 3.0.0-beta.3 3.74.2 3.0.0-beta.30 3.74.3 3.0.0-beta.31 3.75.0 3.0.0-beta.32 3.75.1 3.0.0-beta.33 3.76.0 3.0.0-beta.33.1 3.77.0 3.0.0-beta.34.0.0 3.77.1 3.0.0-beta.36.0.0 3.78.0 3.0.0-beta.36.0.1 3.79.0 3.0.0-beta.36.2.0 3.8 3.0.0-beta.36.3.0 3.8.1 3.0.0-beta.36.3.1 3.8.2 3.0.0-beta.37.0.0 3.8.3 3.0.0-beta.4 3.8.4 3.0.0-beta.5 3.8.5 3.0.0-beta.6 3.8.6 3.0.0-beta.7 3.80.0 3.0.0-beta.7.1 3.81.0 3.0.0-beta.8 3.82.0 3.0.0-beta.9 3.83.0 3.0.0-rc.1.0.0 3.84.0 3.0.0-rc.1.0.1 3.84.1 3.0.0-rc.1.0.2 3.85.0 3.0.0-rc.1.0.3 3.85.1 3.0.0-rc.1.0.4 3.86.0 3.0.0-rc.2.0.0 3.87.0 3.0.0-rc.2.0.1 3.87.1 3.0.0-rc.2.0.2 3.87.2 3.0.0-rc.2.0.3 3.88.0 3.0.1 3.88.1 3.0.2 3.88.2 3.0.3 3.89.0 3.0.4 3.89.1 3.0.5 3.89.2 3.0.6 3.89.3 3.0.7 3.89.4 3.0.8 3.9.0 3.0.9 3.9.1 3.1.0 3.90.0 3.10 3.90.1 3.10.1 3.90.2 3.100.0 3.91.0 3.100.1 3.91.1 3.100.2 3.92.0 3.101.0 3.92.1 3.101.1 3.93.0 3.102.0 3.93.1 3.102.1 3.94.0 3.103.0 3.95.0 3.103.1 3.95.1 3.11.0 3.96.0 3.11.1 3.96.1 3.11.2 3.97.0 3.11.3 3.98.0 3.11.4 3.98.1 3.11.5 3.99.0 3.12.0 3.99.1 3.12.1 4.0.0 3.13.0 4.0.1 3.14.0 4.1.0 3.14.1 4.1.1 3.15.0 4.10.0 3.16.0 4.11.0 3.16.1 4.11.1 3.16.2 4.12.0 3.16.3 4.12.1 3.17.0 4.12.2 3.17.1 4.13.0 3.17.2 4.14.0 3.18.0 4.15.0 3.18.1 4.16.0 3.18.2 4.17.0 3.19.0 4.17.1 3.19.1 4.18.0 3.19.2 4.18.1 3.19.3 4.19.0 3.2.0 4.2.0 3.2.1 4.20.0 3.2.2 4.20.1 3.2.3 4.20.2 3.2.4 4.21.0 3.2.5 4.22.0 3.20.0 4.22.1 3.21.0 4.22.2 3.21.1 4.23.0 3.22.0 4.24.0 3.23.0 4.25.0 3.23.1 4.26.0 3.23.2 4.26.1 3.24.0 4.27.0 3.25.0 4.28.0 3.25.1 4.29.0 3.26.0 4.3.0 3.26.1 4.3.1 3.27.0 4.30.0 3.28.0 4.31.0 3.29.0 4.31.1 3.3.0 4.32.0 3.3.1 4.33.0 3.3.2 4.34.0 3.3.3 4.35.0 3.3.4 4.35.1 3.3.5 4.36.0 3.3.6 4.37.0 3.30.0 4.38.0 3.31.0 4.39.0 3.31.1 4.4.0 3.32.0 4.40.0 3.32.1 4.41.0 3.32.2 4.41.1 3.33.0 4.41.2 3.34.0 4.41.3 3.34.1 4.42.0 3.34.2 4.42.1 3.34.3 3.34.4 3.35.0 3.35.1 3.35.3 3.35.4 3.36.0 3.37.0 3.37.1 3.37.2 3.37.3 3.38.0 3.38.1 3.39.0 3.39.1 3.39.2 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.40.0 3.40.1 3.41.0 3.41.1 3.41.2 3.42.0 3.42.1 3.42.2 3.42.3 3.43.0 3.43.1 3.44.0 3.45.0 3.45.1 3.46.0 3.46.1 3.46.10 3.46.11 3.46.12 3.46.13 3.46.14 3.46.2 3.46.3 3.46.4 3.46.5 3.46.6 3.46.7 3.46.8 3.46.9 3.47.0 3.47.1 3.47.10 3.47.11 3.47.2 3.47.3 3.47.5 3.47.6 3.47.7 3.47.9 3.48.0 3.48.1 3.49.0 3.49.1 3.5.0 3.5.1 3.50.0 3.51.0 3.51.1 3.51.2 3.52.0 3.53.0 3.54.0 3.54.1 3.54.2 3.54.3 3.55.0 3.55.1 3.56.0 3.56.1 3.56.2 3.57.0 3.57.1 3.58.0 3.59.0 3.59.1 3.59.2 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.60.0 3.60.1 3.60.10 3.60.11 3.60.12 3.60.2 3.60.3 3.60.4 3.60.6 3.60.7 3.60.8 3.60.9 3.61.0 3.62.0 3.62.1 3.63.0 3.64.0 3.64.1 3.64.2 3.64.3 3.65.0 trunk 3.65.1 3.0.0 3.66.0 3.0.0-beta.1 3.67.0 3.0.0-beta.10 3.67.1 3.0.0-beta.11 3.68.0 3.0.0-beta.12 3.69.0 3.0.0-beta.13 3.69.1 3.0.0-beta.14 3.7.0
mailpoet / lib / Cron / CronWorkerRunner.php
mailpoet / lib / Cron Last commit date
ActionScheduler 3 years ago Triggers 3 years ago Workers 3 years ago CronHelper.php 3 years ago CronTrigger.php 3 years ago CronWorkerInterface.php 3 years ago CronWorkerRunner.php 3 years ago CronWorkerScheduler.php 3 years ago Daemon.php 3 years ago DaemonActionSchedulerRunner.php 3 years ago DaemonHttpRunner.php 3 years ago Supervisor.php 3 years ago index.php 4 years ago
CronWorkerRunner.php
198 lines
1 <?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
2
3 namespace MailPoet\Cron;
4
5 if (!defined('ABSPATH')) exit;
6
7
8 use MailPoet\Entities\ScheduledTaskEntity;
9 use MailPoet\Logging\LoggerFactory;
10 use MailPoet\Newsletter\Sending\ScheduledTasksRepository;
11 use MailPoet\WP\Functions as WPFunctions;
12 use MailPoetVendor\Carbon\Carbon;
13
14 class CronWorkerRunner {
15 const TASK_BATCH_SIZE = 5;
16 const TASK_RUN_TIMEOUT = 120;
17 const TIMED_OUT_TASK_RESCHEDULE_TIMEOUT = 5;
18
19 /** @var float */
20 private $timer;
21
22 /** @var CronHelper */
23 private $cronHelper;
24
25 /** @var CronWorkerScheduler */
26 private $cronWorkerScheduler;
27
28 /** @var WPFunctions */
29 private $wp;
30
31 /** @var ScheduledTasksRepository */
32 private $scheduledTasksRepository;
33
34 /** @var LoggerFactory */
35 private $loggerFactory;
36
37 public function __construct(
38 CronHelper $cronHelper,
39 CronWorkerScheduler $cronWorkerScheduler,
40 WPFunctions $wp,
41 ScheduledTasksRepository $scheduledTasksRepository,
42 LoggerFactory $loggerFactory
43 ) {
44 $this->timer = microtime(true);
45 $this->cronHelper = $cronHelper;
46 $this->cronWorkerScheduler = $cronWorkerScheduler;
47 $this->wp = $wp;
48 $this->scheduledTasksRepository = $scheduledTasksRepository;
49 $this->loggerFactory = $loggerFactory;
50 }
51
52 public function run(CronWorkerInterface $worker) {
53 // abort if execution limit is reached
54 $this->cronHelper->enforceExecutionLimit($this->timer);
55 $dueTasks = $this->getDueTasks($worker);
56 $runningTasks = $this->getRunningTasks($worker);
57
58 if (!$worker->checkProcessingRequirements()) {
59 foreach (array_merge($dueTasks, $runningTasks) as $task) {
60 $this->scheduledTasksRepository->remove($task);
61 $this->scheduledTasksRepository->flush();
62 }
63 return false;
64 }
65
66 $worker->init();
67
68 if (!$dueTasks && !$runningTasks) {
69 if ($worker->scheduleAutomatically()) {
70 $this->cronWorkerScheduler->schedule($worker->getTaskType(), $worker->getNextRunDate());
71 }
72 return false;
73 }
74
75 try {
76 foreach ($dueTasks as $task) {
77 $this->prepareTask($worker, $task);
78 }
79 // Re-fetch running tasks so that we can process tasks that were just prepared
80 $runningTasks = $this->getRunningTasks($worker);
81 foreach ($runningTasks as $task) {
82 $this->processTask($worker, $task);
83 }
84 } catch (\Exception $e) {
85 if (isset($task) && $task && $e->getCode() !== CronHelper::DAEMON_EXECUTION_LIMIT_REACHED) {
86 /**
87 * ToDo: Use \LoggerFactory::TOPIC_CRON as logger topic, once it is available
88 */
89 $this->loggerFactory->getLogger()->error($e->getMessage(), ['error' => $e]);
90 $this->cronWorkerScheduler->rescheduleProgressively($task);
91 }
92 throw $e;
93 }
94
95 return true;
96 }
97
98 private function getDueTasks(CronWorkerInterface $worker) {
99 return $this->scheduledTasksRepository->findDueByType($worker->getTaskType(), self::TASK_BATCH_SIZE);
100 }
101
102 private function getRunningTasks(CronWorkerInterface $worker) {
103 return $this->scheduledTasksRepository->findRunningByType($worker->getTaskType(), self::TASK_BATCH_SIZE);
104 }
105
106 private function prepareTask(CronWorkerInterface $worker, ScheduledTaskEntity $task) {
107 // abort if execution limit is reached
108 $this->cronHelper->enforceExecutionLimit($this->timer);
109
110 $prepareCompleted = $worker->prepareTaskStrategy($task, $this->timer);
111
112 if ($prepareCompleted) {
113 $task->setStatus(null);
114 $this->scheduledTasksRepository->persist($task);
115 $this->scheduledTasksRepository->flush();
116 }
117 }
118
119 private function processTask(CronWorkerInterface $worker, ScheduledTaskEntity $task) {
120 // abort if execution limit is reached
121 $this->cronHelper->enforceExecutionLimit($this->timer);
122
123 if (!$worker->supportsMultipleInstances()) {
124 if ($this->rescheduleOutdated($task)) {
125 return false;
126 }
127 if ($this->isInProgress($task)) {
128 return false;
129 }
130 }
131
132 $this->startProgress($task);
133
134 try {
135 $completed = $worker->processTaskStrategy($task, $this->timer);
136 } catch (\Exception $e) {
137 $this->stopProgress($task);
138 throw $e;
139 }
140
141 if ($completed) {
142 $this->complete($task);
143 }
144
145 $this->stopProgress($task);
146
147 return (bool)$completed;
148 }
149
150 private function rescheduleOutdated(ScheduledTaskEntity $task) {
151 $currentTime = Carbon::createFromTimestamp($this->wp->currentTime('timestamp'));
152
153 if (empty($task->getUpdatedAt())) {
154 // missing updatedAt, consider this task outdated (set year to 2000) and reschedule
155 $updatedAt = Carbon::createFromDate(2000);
156 } else if (!$task->getUpdatedAt() instanceof Carbon) {
157 $updatedAt = new Carbon($task->getUpdatedAt());
158 } else {
159 $updatedAt = $task->getUpdatedAt();
160 }
161
162 // If the task is running for too long consider it stuck and reschedule
163 if (!empty($task->getUpdatedAt()) && $updatedAt->diffInMinutes($currentTime, false) > self::TASK_RUN_TIMEOUT) {
164 $this->stopProgress($task);
165 $this->cronWorkerScheduler->reschedule($task, self::TIMED_OUT_TASK_RESCHEDULE_TIMEOUT);
166 return true;
167 }
168 return false;
169 }
170
171 private function isInProgress(ScheduledTaskEntity $task) {
172 if ($task->getInProgress()) {
173 // Do not run multiple instances of the task
174 return true;
175 }
176 return false;
177 }
178
179 private function startProgress(ScheduledTaskEntity $task) {
180 $task->setInProgress(true);
181 $this->scheduledTasksRepository->persist($task);
182 $this->scheduledTasksRepository->flush();
183 }
184
185 private function stopProgress(ScheduledTaskEntity $task) {
186 $task->setInProgress(false);
187 $this->scheduledTasksRepository->persist($task);
188 $this->scheduledTasksRepository->flush();
189 }
190
191 private function complete(ScheduledTaskEntity $task) {
192 $task->setProcessedAt(Carbon::createFromTimestamp($this->wp->currentTime('timestamp')));
193 $task->setStatus(ScheduledTaskEntity::STATUS_COMPLETED);
194 $this->scheduledTasksRepository->persist($task);
195 $this->scheduledTasksRepository->flush();
196 }
197 }
198