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 / CliCommands / TaskAdder.php
mailpoet / lib / Cron / CliCommands Last commit date
ClaimedTaskRunner.php 1 month ago Cli.php 1 month ago CronCommand.php 1 month ago DaemonRunner.php 1 month ago ExecutionLimitOverride.php 1 month ago ScheduledTaskResolver.php 1 month ago ScheduledTasksLister.php 1 month ago TaskAdder.php 1 month ago TaskCanceller.php 1 month ago TaskRunner.php 1 month ago TaskTrigger.php 1 month ago WorkerTypesCatalog.php 1 month ago index.php 1 month ago
TaskAdder.php
155 lines
1 <?php declare(strict_types = 1);
2
3 namespace MailPoet\Cron\CliCommands;
4
5 if (!defined('ABSPATH')) exit;
6
7
8 use Exception;
9 use InvalidArgumentException;
10 use MailPoet\Entities\ScheduledTaskEntity;
11 use MailPoet\Newsletter\Sending\ScheduledTasksRepository;
12 use MailPoetVendor\Carbon\Carbon;
13
14 /**
15 * Adds a new scheduled task for a standard cron worker, optionally claiming and running it in-process.
16 *
17 * Only standard CronWorkerInterface workers are addable (see WorkerTypesCatalog::getAddableTypes());
18 * mailing 'sending'/'stats_notification' rows are created by app flows and are rejected. --run drives a
19 * freshly claimed row through ClaimedTaskRunner, shared with `cron run --task-id`.
20 *
21 * See doc/wp-cli-cron-commands.md for command behaviour.
22 */
23 class TaskAdder {
24 const PRIORITY_MAP = [
25 'high' => ScheduledTaskEntity::PRIORITY_HIGH,
26 'medium' => ScheduledTaskEntity::PRIORITY_MEDIUM,
27 'low' => ScheduledTaskEntity::PRIORITY_LOW,
28 ];
29
30 private WorkerTypesCatalog $workerTypesCatalog;
31
32 private ScheduledTasksRepository $scheduledTasksRepository;
33
34 private ClaimedTaskRunner $claimedTaskRunner;
35
36 public function __construct(
37 WorkerTypesCatalog $workerTypesCatalog,
38 ScheduledTasksRepository $scheduledTasksRepository,
39 ClaimedTaskRunner $claimedTaskRunner
40 ) {
41 $this->workerTypesCatalog = $workerTypesCatalog;
42 $this->scheduledTasksRepository = $scheduledTasksRepository;
43 $this->claimedTaskRunner = $claimedTaskRunner;
44 }
45
46 /**
47 * @return array{id: int, type: string, action: string, message: string, run: array{completed: bool, limit_reached: bool, message: string}|null}
48 */
49 public function add(string $type, ?string $at, ?int $in, string $priority, bool $force, bool $run): array {
50 $this->workerTypesCatalog->assertAddableType($type);
51 $priorityValue = $this->resolvePriority($priority);
52
53 if ($run && ($at !== null || $in !== null)) {
54 throw new InvalidArgumentException('--run cannot be combined with --at or --in. A claimed task runs immediately.');
55 }
56
57 if ($run) {
58 return $this->claimAndRun($type, $priorityValue);
59 }
60
61 $scheduledAt = $this->resolveScheduledAt($at, $in);
62
63 if (!$force) {
64 $existing = $this->scheduledTasksRepository->findScheduledTask($type);
65 if ($existing instanceof ScheduledTaskEntity) {
66 $existingId = (int)$existing->getId();
67 return [
68 'id' => $existingId,
69 'type' => $type,
70 'action' => 'duplicate',
71 'message' => sprintf("A task of type '%s' is already scheduled as task %d. Use --force to add another.", $type, $existingId),
72 'run' => null,
73 ];
74 }
75 }
76
77 $task = $this->createTask($type, $priorityValue, $scheduledAt);
78
79 return [
80 'id' => (int)$task->getId(),
81 'type' => $type,
82 'action' => 'created',
83 'message' => sprintf("Added task %d (%s), scheduled for %s, priority %s.", $task->getId(), $type, $scheduledAt->format('Y-m-d H:i:s'), $priority),
84 'run' => null,
85 ];
86 }
87
88 private function createTask(string $type, int $priority, Carbon $scheduledAt): ScheduledTaskEntity {
89 $task = new ScheduledTaskEntity();
90 $task->setType($type);
91 $task->setStatus(ScheduledTaskEntity::STATUS_SCHEDULED);
92 $task->setPriority($priority);
93 $task->setScheduledAt($scheduledAt);
94 $this->scheduledTasksRepository->persist($task);
95 $this->scheduledTasksRepository->flush();
96 return $task;
97 }
98
99 /**
100 * Claims a fresh row (status STATUS_CLI) and processes exactly that one task. The duplicate check is
101 * intentionally skipped: the claim is a fresh, independently-owned row, never a "scheduled
102 * duplicate", so --run ignores --force entirely.
103 *
104 * @return array{id: int, type: string, action: string, message: string, run: array{completed: bool, limit_reached: bool, message: string}}
105 */
106 private function claimAndRun(string $type, int $priority): array {
107 $worker = $this->workerTypesCatalog->getWorkerByType($type);
108 if ($worker === null) {
109 // Unreachable: assertAddableType already restricts to types with a standard worker.
110 throw new InvalidArgumentException("Task type '{$type}' has no runnable worker.");
111 }
112
113 $task = $this->claimedTaskRunner->claimNew($type, $priority);
114 $taskId = (int)$task->getId();
115
116 $runResult = $this->claimedTaskRunner->run($worker, $task);
117
118 return [
119 'id' => $taskId,
120 'type' => $type,
121 'action' => 'claimed',
122 'message' => sprintf("Claimed task %d (%s) and ran it in this process.", $taskId, $type),
123 'run' => $runResult,
124 ];
125 }
126
127 private function resolveScheduledAt(?string $at, ?int $in): Carbon {
128 if ($at !== null && $in !== null) {
129 throw new InvalidArgumentException('--at and --in cannot be used together. Pick one.');
130 }
131
132 if ($at !== null) {
133 try {
134 return Carbon::parse($at)->millisecond(0);
135 } catch (Exception $e) {
136 throw new InvalidArgumentException("Could not parse --at value '{$at}'. Use a date/time like '2026-01-01 09:00' or 'tomorrow 8am'.");
137 }
138 }
139
140 if ($in !== null) {
141 return Carbon::now()->millisecond(0)->addSeconds($in);
142 }
143
144 return Carbon::now()->millisecond(0);
145 }
146
147 private function resolvePriority(string $priority): int {
148 if (!isset(self::PRIORITY_MAP[$priority])) {
149 $valid = implode(', ', array_keys(self::PRIORITY_MAP));
150 throw new InvalidArgumentException("Invalid priority '{$priority}'. Valid values: {$valid}.");
151 }
152 return self::PRIORITY_MAP[$priority];
153 }
154 }
155