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 / Workers / SubscribersSegmentsCountSync.php
mailpoet / lib / Cron / Workers Last commit date
Automations 1 year ago KeyCheck 1 year ago SendingQueue 6 days ago StatsNotifications 2 months ago AuthorizedSendingEmailsCheck.php 3 years ago BackfillEngagementData.php 1 year ago Bounce.php 6 days ago BounceTaskSubscribersCleanup.php 1 month ago BulkConfirmationEmailResend.php 2 months ago ExportFilesCleanup.php 2 months ago InactiveSubscribersMaintenance.php 2 weeks ago LogCleanup.php 10 months ago Mixpanel.php 9 months ago NewsletterTemplateThumbnails.php 1 year ago ReEngagementEmailsScheduler.php 1 year ago Scheduler.php 2 months ago SendingQueueBodyCleanup.php 2 months ago SendingTaskSubscribersCleanup.php 2 months ago SimpleWorker.php 1 year ago StatisticsExport.php 2 months ago SubscriberLimitNotificationWorker.php 2 months ago SubscriberLinkTokens.php 1 year ago SubscribersCountCacheRecalculation.php 2 weeks ago SubscribersEngagementScore.php 4 days ago SubscribersLastEngagement.php 2 months ago SubscribersSegmentsCountSync.php 2 weeks ago SubscribersStatsReport.php 1 year ago Tracks.php 9 months ago UnconfirmedSubscribersCleanup.php 2 months ago UnsubscribeTokens.php 1 month ago WooCommercePastOrders.php 1 year ago WooCommerceSync.php 3 years ago WorkersFactory.php 2 weeks ago index.php 3 years ago
SubscribersSegmentsCountSync.php
91 lines
1 <?php declare(strict_types = 1);
2
3 namespace MailPoet\Cron\Workers;
4
5 if (!defined('ABSPATH')) exit;
6
7
8 use MailPoet\Doctrine\WPDB\Connection;
9 use MailPoet\Entities\ScheduledTaskEntity;
10 use MailPoet\Entities\SubscriberEntity;
11 use MailPoet\Segments\SegmentSubscribersRepository;
12 use MailPoet\Subscribers\SegmentsCountRecalculator;
13 use MailPoetVendor\Doctrine\ORM\EntityManager;
14
15 /**
16 * Populates and reconciles SubscriberEntity::$segmentsCount.
17 *
18 * The first run is the backfill: it sweeps the whole subscribers table by id
19 * range, recomputes segments_count for every row, and then calls
20 * SegmentSubscribersRepository::markSegmentsCountColumnReady() so reads start
21 * trusting the column.
22 *
23 * Every subsequent (weekly) run is the reconcile backstop: it re-sweeps the
24 * table to repair any drift left by a write path that forgot to update the
25 * column. Both phases use the same idempotent recompute, so the value always
26 * converges. Work is chunked and bounded by enforceExecutionLimit() so the
27 * sweep never runs as one long query and never blocks a request.
28 */
29 class SubscribersSegmentsCountSync extends SimpleWorker {
30 const TASK_TYPE = 'subscribers_segments_count_sync';
31 const SUPPORT_MULTIPLE_INSTANCES = false;
32
33 /** @var EntityManager */
34 private $entityManager;
35
36 /** @var SegmentsCountRecalculator */
37 private $segmentsCountRecalculator;
38
39 /** @var SegmentSubscribersRepository */
40 private $segmentSubscribersRepository;
41
42 public function __construct(
43 EntityManager $entityManager,
44 SegmentsCountRecalculator $segmentsCountRecalculator,
45 SegmentSubscribersRepository $segmentSubscribersRepository
46 ) {
47 parent::__construct();
48 $this->entityManager = $entityManager;
49 $this->segmentsCountRecalculator = $segmentsCountRecalculator;
50 $this->segmentSubscribersRepository = $segmentSubscribersRepository;
51 }
52
53 public function processTaskStrategy(ScheduledTaskEntity $task, $timer): bool {
54 // The recalculator relies on UPDATE ... LEFT JOIN, which the SQLite
55 // integration in WordPress Playground does not support. Make the task a
56 // no-op there and never flip the backfill flag, so reads stay on the
57 // anti-join fallback instead of trusting an unpopulated column.
58 if (Connection::isSQLite()) {
59 return true;
60 }
61
62 $meta = $task->getMeta();
63 $lastId = isset($meta['last_subscriber_id']) ? (int)$meta['last_subscriber_id'] : 0;
64 $highestId = $this->getHighestSubscriberId();
65
66 while ($lastId < $highestId) {
67 $this->segmentsCountRecalculator->recalculateForIdRange($lastId + 1, $lastId + SegmentsCountRecalculator::BATCH_SIZE);
68 $lastId += SegmentsCountRecalculator::BATCH_SIZE;
69 $task->setMeta(['last_subscriber_id' => $lastId]);
70 $this->scheduledTasksRepository->persist($task);
71 $this->scheduledTasksRepository->flush();
72 $this->cronHelper->enforceExecutionLimit($timer); // throws and reschedules when over the limit
73 }
74
75 // The whole table has been recomputed: reads can trust segments_count now.
76 // The cursor is intentionally left in place: each weekly reconcile run is a
77 // fresh task with empty meta, so it sweeps from id 0 again on its own. And if
78 // markSegmentsCountColumnReady() throws, the retry just re-runs the flag flip
79 // (the while loop is already exhausted) instead of re-sweeping the table.
80 $this->segmentSubscribersRepository->markSegmentsCountColumnReady();
81
82 return true;
83 }
84
85 private function getHighestSubscriberId(): int {
86 $subscribersTable = $this->entityManager->getClassMetadata(SubscriberEntity::class)->getTableName();
87 $result = $this->entityManager->getConnection()->executeQuery("SELECT MAX(id) FROM $subscribersTable LIMIT 1;")->fetchNumeric();
88 return is_array($result) && isset($result[0]) && is_numeric($result[0]) ? (int)$result[0] : 0;
89 }
90 }
91