PluginProbe ʕ •ᴥ•ʔ
MailPoet – Newsletters, Email Marketing, and Automation / 5.34.2
MailPoet – Newsletters, Email Marketing, and Automation v5.34.2
5.34.2 5.34.1 5.34.0 5.33.1 5.33.0 5.32.0 5.31.0 5.30.0 5.29.0 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 2 months ago CliCommands 1 month ago Triggers 2 months ago Workers 3 days ago CronHelper.php 2 months ago CronTrigger.php 2 years ago CronWorkerInterface.php 3 years ago CronWorkerRunner.php 2 months ago CronWorkerScheduler.php 10 months ago Daemon.php 3 days ago DaemonActionSchedulerRunner.php 6 months ago DaemonHttpRunner.php 2 months ago Supervisor.php 3 years ago index.php 3 years ago
CronWorkerRunner.php
192 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 MailPoetVendor\Carbon\Carbon;
12
13 class CronWorkerRunner {
14 const TASK_BATCH_SIZE = 5;
15 const TASK_RUN_TIMEOUT = 120;
16 const TIMED_OUT_TASK_RESCHEDULE_TIMEOUT = 5;
17
18 /** @var float */
19 private $timer;
20
21 /** @var CronHelper */
22 private $cronHelper;
23
24 /** @var CronWorkerScheduler */
25 private $cronWorkerScheduler;
26
27 /** @var ScheduledTasksRepository */
28 private $scheduledTasksRepository;
29
30 /** @var LoggerFactory */
31 private $loggerFactory;
32
33 public function __construct(
34 CronHelper $cronHelper,
35 CronWorkerScheduler $cronWorkerScheduler,
36 ScheduledTasksRepository $scheduledTasksRepository,
37 LoggerFactory $loggerFactory
38 ) {
39 $this->timer = microtime(true);
40 $this->cronHelper = $cronHelper;
41 $this->cronWorkerScheduler = $cronWorkerScheduler;
42 $this->scheduledTasksRepository = $scheduledTasksRepository;
43 $this->loggerFactory = $loggerFactory;
44 }
45
46 public function run(CronWorkerInterface $worker) {
47 // abort if execution limit is reached
48 $this->cronHelper->enforceExecutionLimit($this->timer);
49 $dueTasks = $this->getDueTasks($worker);
50 $runningTasks = $this->getRunningTasks($worker);
51
52 if (!$worker->checkProcessingRequirements()) {
53 foreach (array_merge($dueTasks, $runningTasks) as $task) {
54 $this->scheduledTasksRepository->remove($task);
55 $this->scheduledTasksRepository->flush();
56 }
57 return false;
58 }
59
60 $worker->init();
61
62 if (!$dueTasks && !$runningTasks) {
63 if ($worker->scheduleAutomatically()) {
64 $this->cronWorkerScheduler->schedule($worker->getTaskType(), $worker->getNextRunDate());
65 }
66 return false;
67 }
68
69 try {
70 foreach ($dueTasks as $task) {
71 $this->prepareTask($worker, $task);
72 }
73 // Re-fetch running tasks so that we can process tasks that were just prepared
74 $runningTasks = $this->getRunningTasks($worker);
75 foreach ($runningTasks as $task) {
76 $this->processTask($worker, $task);
77 }
78 } catch (\Exception $e) {
79 if (isset($task) && $task && $e->getCode() !== CronHelper::DAEMON_EXECUTION_LIMIT_REACHED) {
80 /**
81 * ToDo: Use \LoggerFactory::TOPIC_CRON as logger topic, once it is available
82 */
83 $this->loggerFactory->getLogger()->error($e->getMessage(), ['error' => $e]);
84 $this->cronWorkerScheduler->rescheduleProgressively($task);
85 }
86 throw $e;
87 }
88
89 return true;
90 }
91
92 private function getDueTasks(CronWorkerInterface $worker) {
93 return $this->scheduledTasksRepository->findDueByType($worker->getTaskType(), self::TASK_BATCH_SIZE);
94 }
95
96 private function getRunningTasks(CronWorkerInterface $worker) {
97 return $this->scheduledTasksRepository->findRunningByType($worker->getTaskType(), self::TASK_BATCH_SIZE);
98 }
99
100 private function prepareTask(CronWorkerInterface $worker, ScheduledTaskEntity $task) {
101 // abort if execution limit is reached
102 $this->cronHelper->enforceExecutionLimit($this->timer);
103
104 $prepareCompleted = $worker->prepareTaskStrategy($task, $this->timer);
105
106 if ($prepareCompleted) {
107 $task->setStatus(null);
108 $this->scheduledTasksRepository->persist($task);
109 $this->scheduledTasksRepository->flush();
110 }
111 }
112
113 private function processTask(CronWorkerInterface $worker, ScheduledTaskEntity $task) {
114 // abort if execution limit is reached
115 $this->cronHelper->enforceExecutionLimit($this->timer);
116
117 if (!$worker->supportsMultipleInstances()) {
118 if ($this->rescheduleOutdated($task)) {
119 return false;
120 }
121 if ($this->isInProgress($task)) {
122 return false;
123 }
124 }
125
126 $this->startProgress($task);
127
128 try {
129 $completed = $worker->processTaskStrategy($task, $this->timer);
130 } catch (\Exception $e) {
131 $this->stopProgress($task);
132 throw $e;
133 }
134
135 if ($completed) {
136 $this->complete($task);
137 }
138
139 $this->stopProgress($task);
140
141 return (bool)$completed;
142 }
143
144 private function rescheduleOutdated(ScheduledTaskEntity $task) {
145 $currentTime = Carbon::now()->millisecond(0);
146
147 if (empty($task->getUpdatedAt())) {
148 // missing updatedAt, consider this task outdated (set year to 2000) and reschedule
149 $updatedAt = Carbon::createFromDate(2000);
150 } else if (!$task->getUpdatedAt() instanceof Carbon) {
151 $updatedAt = new Carbon($task->getUpdatedAt());
152 } else {
153 $updatedAt = $task->getUpdatedAt();
154 }
155
156 // If the task is running for too long consider it stuck and reschedule
157 if ($updatedAt->diffInMinutes($currentTime, false) > self::TASK_RUN_TIMEOUT) {
158 $this->stopProgress($task);
159 $this->cronWorkerScheduler->reschedule($task, self::TIMED_OUT_TASK_RESCHEDULE_TIMEOUT);
160 return true;
161 }
162 return false;
163 }
164
165 private function isInProgress(ScheduledTaskEntity $task) {
166 if ($task->getInProgress()) {
167 // Do not run multiple instances of the task
168 return true;
169 }
170 return false;
171 }
172
173 private function startProgress(ScheduledTaskEntity $task) {
174 $task->setInProgress(true);
175 $this->scheduledTasksRepository->persist($task);
176 $this->scheduledTasksRepository->flush();
177 }
178
179 private function stopProgress(ScheduledTaskEntity $task) {
180 $task->setInProgress(false);
181 $this->scheduledTasksRepository->persist($task);
182 $this->scheduledTasksRepository->flush();
183 }
184
185 private function complete(ScheduledTaskEntity $task) {
186 $task->setProcessedAt(Carbon::now()->millisecond(0));
187 $task->setStatus(ScheduledTaskEntity::STATUS_COMPLETED);
188 $this->scheduledTasksRepository->persist($task);
189 $this->scheduledTasksRepository->flush();
190 }
191 }
192