init
This commit is contained in:
@@ -0,0 +1,272 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\Cron\Triggers;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
|
||||
use MailPoet\Config\ServicesChecker;
|
||||
use MailPoet\Cron\CronHelper;
|
||||
use MailPoet\Cron\Supervisor;
|
||||
use MailPoet\Cron\Workers\Bounce as BounceWorker;
|
||||
use MailPoet\Cron\Workers\KeyCheck\PremiumKeyCheck as PremiumKeyCheckWorker;
|
||||
use MailPoet\Cron\Workers\KeyCheck\SendingServiceKeyCheck as SendingServiceKeyCheckWorker;
|
||||
use MailPoet\Cron\Workers\Scheduler as SchedulerWorker;
|
||||
use MailPoet\Cron\Workers\SendingQueue\SendingQueue as SendingQueueWorker;
|
||||
use MailPoet\Cron\Workers\SubscribersStatsReport;
|
||||
use MailPoet\Cron\Workers\WorkersFactory;
|
||||
use MailPoet\Entities\ScheduledTaskEntity;
|
||||
use MailPoet\Mailer\MailerLog;
|
||||
use MailPoet\Newsletter\Sending\ScheduledTasksRepository;
|
||||
use MailPoet\Services\Bridge;
|
||||
use MailPoet\Settings\SettingsController;
|
||||
use MailPoet\Util\Helpers;
|
||||
use MailPoet\WP\Functions as WPFunctions;
|
||||
use MailPoetVendor\Doctrine\ORM\EntityManager;
|
||||
|
||||
class WordPress {
|
||||
const SCHEDULED_IN_THE_PAST = 'past';
|
||||
const SCHEDULED_IN_THE_FUTURE = 'future';
|
||||
|
||||
const RUN_INTERVAL = -1; // seconds
|
||||
const LAST_RUN_AT_SETTING = 'cron_trigger_wordpress.last_run_at';
|
||||
|
||||
private $tasksCounts;
|
||||
|
||||
/** @var CronHelper */
|
||||
private $cronHelper;
|
||||
|
||||
/** @var Supervisor */
|
||||
private $supervisor;
|
||||
|
||||
/** @var SettingsController */
|
||||
private $settings;
|
||||
|
||||
/** @var WPFunctions */
|
||||
private $wp;
|
||||
|
||||
/** @var ServicesChecker */
|
||||
private $serviceChecker;
|
||||
|
||||
/** @var ScheduledTasksRepository */
|
||||
private $scheduledTasksRepository;
|
||||
|
||||
/** @var EntityManager */
|
||||
private $entityManager;
|
||||
|
||||
public function __construct(
|
||||
CronHelper $cronHelper,
|
||||
Supervisor $supervisor,
|
||||
SettingsController $settings,
|
||||
ServicesChecker $serviceChecker,
|
||||
WPFunctions $wp,
|
||||
ScheduledTasksRepository $scheduledTasksRepository,
|
||||
EntityManager $entityManager
|
||||
) {
|
||||
$this->supervisor = $supervisor;
|
||||
$this->settings = $settings;
|
||||
$this->wp = $wp;
|
||||
$this->cronHelper = $cronHelper;
|
||||
$this->serviceChecker = $serviceChecker;
|
||||
$this->scheduledTasksRepository = $scheduledTasksRepository;
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
|
||||
public function run() {
|
||||
try {
|
||||
if (!$this->checkRunInterval()) {
|
||||
return false;
|
||||
}
|
||||
if (!$this->checkExecutionRequirements()) {
|
||||
$this->stop();
|
||||
return;
|
||||
}
|
||||
|
||||
$this->supervisor->init();
|
||||
return $this->supervisor->checkDaemon();
|
||||
} catch (\Exception $e) {
|
||||
$mySqlGoneAwayMessage = Helpers::mySqlGoneAwayExceptionHandler($e);
|
||||
if ($mySqlGoneAwayMessage) {
|
||||
throw new \Exception($mySqlGoneAwayMessage, 0, $e);
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
private function checkRunInterval(): bool {
|
||||
$runInterval = $this->wp->applyFilters('mailpoet_cron_trigger_wordpress_run_interval', self::RUN_INTERVAL);
|
||||
if ($runInterval === -1) {
|
||||
return true;
|
||||
}
|
||||
$lastRunAt = (int)$this->settings->get(self::LAST_RUN_AT_SETTING, 0);
|
||||
$runIntervalElapsed = (time() - $lastRunAt) >= $runInterval;
|
||||
if ($runIntervalElapsed) {
|
||||
$this->settings->set(self::LAST_RUN_AT_SETTING, time());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function resetRunInterval(): void {
|
||||
$settings = SettingsController::getInstance();
|
||||
$settings->set(self::LAST_RUN_AT_SETTING, 0);
|
||||
}
|
||||
|
||||
public function checkExecutionRequirements(): bool {
|
||||
if ($this->wp->wpIsMaintenanceMode()) {
|
||||
// Skip if WP is currently in maintenance mode
|
||||
// The maintenance mode is activated when WP core or a plugin update is in progress
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->loadTasksCounts();
|
||||
|
||||
// Because a lot of workers has the same pattern for check if it's active we can use a loop here
|
||||
$isSimpleWorkerActive = false;
|
||||
foreach (WorkersFactory::SIMPLE_WORKER_TYPES as $simpleWorkerType) {
|
||||
$tasksCount = $this->getTasksCount([
|
||||
'type' => $simpleWorkerType,
|
||||
'scheduled_in' => [self::SCHEDULED_IN_THE_PAST],
|
||||
'status' => ['null', ScheduledTaskEntity::STATUS_SCHEDULED],
|
||||
]);
|
||||
if ($tasksCount) {
|
||||
$isSimpleWorkerActive = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
$this->isSendingQueueActive()
|
||||
|| $this->isBounceActive()
|
||||
|| $this->isSendingServiceKeyCheckActive()
|
||||
|| $this->isPremiumKeyCheckActive()
|
||||
|| $this->isSubscriberStatsReportActive()
|
||||
|| $isSimpleWorkerActive
|
||||
);
|
||||
}
|
||||
|
||||
public function stop() {
|
||||
$cronDaemon = $this->cronHelper->getDaemon();
|
||||
if ($cronDaemon) {
|
||||
$this->cronHelper->deactivateDaemon($cronDaemon);
|
||||
}
|
||||
}
|
||||
|
||||
private function isSendingQueueActive(): bool {
|
||||
$scheduledQueues = $this->scheduledTasksRepository->findScheduledSendingTasks(SchedulerWorker::TASK_BATCH_SIZE);
|
||||
$runningQueues = $this->scheduledTasksRepository->findRunningSendingTasks(SendingQueueWorker::TASK_BATCH_SIZE);
|
||||
$sendingLimitReached = MailerLog::isSendingLimitReached();
|
||||
$sendingIsPaused = MailerLog::isSendingPaused();
|
||||
$sendingWaitingForRetry = MailerLog::isSendingWaitingForRetry();
|
||||
|
||||
return (($scheduledQueues || $runningQueues) && !$sendingLimitReached && !$sendingIsPaused && !$sendingWaitingForRetry);
|
||||
}
|
||||
|
||||
private function isBounceActive(): bool {
|
||||
$mpSendingEnabled = Bridge::isMPSendingServiceEnabled();
|
||||
$bounceDueTasks = $this->getTasksCount([
|
||||
'type' => BounceWorker::TASK_TYPE,
|
||||
'scheduled_in' => [self::SCHEDULED_IN_THE_PAST],
|
||||
'status' => ['null', ScheduledTaskEntity::STATUS_SCHEDULED],
|
||||
]);
|
||||
$bounceFutureTasks = $this->getTasksCount([
|
||||
'type' => BounceWorker::TASK_TYPE,
|
||||
'scheduled_in' => [self::SCHEDULED_IN_THE_FUTURE],
|
||||
'status' => [ScheduledTaskEntity::STATUS_SCHEDULED],
|
||||
]);
|
||||
|
||||
return ($mpSendingEnabled && ($bounceDueTasks || !$bounceFutureTasks));
|
||||
}
|
||||
|
||||
private function isSendingServiceKeyCheckActive(): bool {
|
||||
$mpSendingEnabled = Bridge::isMPSendingServiceEnabled();
|
||||
$msskeycheckDueTasks = $this->getTasksCount([
|
||||
'type' => SendingServiceKeyCheckWorker::TASK_TYPE,
|
||||
'scheduled_in' => [self::SCHEDULED_IN_THE_PAST],
|
||||
'status' => ['null', ScheduledTaskEntity::STATUS_SCHEDULED],
|
||||
]);
|
||||
$msskeycheckFutureTasks = $this->getTasksCount([
|
||||
'type' => SendingServiceKeyCheckWorker::TASK_TYPE,
|
||||
'scheduled_in' => [self::SCHEDULED_IN_THE_FUTURE],
|
||||
'status' => [ScheduledTaskEntity::STATUS_SCHEDULED],
|
||||
]);
|
||||
|
||||
return ($mpSendingEnabled && ($msskeycheckDueTasks || !$msskeycheckFutureTasks));
|
||||
}
|
||||
|
||||
private function isPremiumKeyCheckActive(): bool {
|
||||
$premiumKeySpecified = Bridge::isPremiumKeySpecified();
|
||||
$premiumKeycheckDueTasks = $this->getTasksCount([
|
||||
'type' => PremiumKeyCheckWorker::TASK_TYPE,
|
||||
'scheduled_in' => [self::SCHEDULED_IN_THE_PAST],
|
||||
'status' => ['null', ScheduledTaskEntity::STATUS_SCHEDULED],
|
||||
]);
|
||||
$premiumKeycheckFutureTasks = $this->getTasksCount([
|
||||
'type' => PremiumKeyCheckWorker::TASK_TYPE,
|
||||
'scheduled_in' => [self::SCHEDULED_IN_THE_FUTURE],
|
||||
'status' => [ScheduledTaskEntity::STATUS_SCHEDULED],
|
||||
]);
|
||||
|
||||
return ($premiumKeySpecified && ($premiumKeycheckDueTasks || !$premiumKeycheckFutureTasks));
|
||||
}
|
||||
|
||||
private function isSubscriberStatsReportActive(): bool {
|
||||
$validAccountKey = $this->serviceChecker->getValidAccountKey();
|
||||
$statsReportDueTasks = $this->getTasksCount([
|
||||
'type' => SubscribersStatsReport::TASK_TYPE,
|
||||
'scheduled_in' => [self::SCHEDULED_IN_THE_PAST],
|
||||
'status' => ['null', ScheduledTaskEntity::STATUS_SCHEDULED],
|
||||
]);
|
||||
$statsReportFutureTasks = $this->getTasksCount([
|
||||
'type' => SubscribersStatsReport::TASK_TYPE,
|
||||
'scheduled_in' => [self::SCHEDULED_IN_THE_FUTURE],
|
||||
'status' => [ScheduledTaskEntity::STATUS_SCHEDULED],
|
||||
]);
|
||||
|
||||
return ($validAccountKey && ($statsReportDueTasks || !$statsReportFutureTasks));
|
||||
}
|
||||
|
||||
private function loadTasksCounts(): void {
|
||||
$scheduledTasksTableName = $this->entityManager->getClassMetadata(ScheduledTaskEntity::class)->getTableName();
|
||||
$sql = "
|
||||
SELECT
|
||||
type,
|
||||
status,
|
||||
count(*) AS count,
|
||||
CASE WHEN scheduled_at <= :now THEN :past ELSE :future END AS scheduled_in
|
||||
FROM $scheduledTasksTableName
|
||||
WHERE deleted_at IS NULL AND (status != :statusCompleted OR status IS NULL)
|
||||
GROUP BY type, status, scheduled_in";
|
||||
|
||||
$stmt = $this->entityManager->getConnection()->prepare($sql);
|
||||
$stmt->bindValue('now', date('Y-m-d H:i:s', $this->wp->currentTime('timestamp', true)));
|
||||
$stmt->bindValue('past', self::SCHEDULED_IN_THE_PAST);
|
||||
$stmt->bindValue('future', self::SCHEDULED_IN_THE_FUTURE);
|
||||
$stmt->bindValue('statusCompleted', ScheduledTaskEntity::STATUS_COMPLETED);
|
||||
$rows = $stmt->executeQuery()->fetchAllAssociative();
|
||||
|
||||
$this->tasksCounts = [];
|
||||
foreach ($rows as $r) {
|
||||
if (empty($this->tasksCounts[$r['type']])) {
|
||||
$this->tasksCounts[$r['type']] = [];
|
||||
}
|
||||
if (empty($this->tasksCounts[$r['type']][$r['scheduled_in']])) {
|
||||
$this->tasksCounts[$r['type']][$r['scheduled_in']] = [];
|
||||
}
|
||||
$this->tasksCounts[$r['type']][$r['scheduled_in']][$r['status'] ?: 'null'] = $r['count'];
|
||||
}
|
||||
}
|
||||
|
||||
private function getTasksCount(array $options): int {
|
||||
$count = 0;
|
||||
$type = $options['type'];
|
||||
foreach ($options['scheduled_in'] as $scheduledIn) {
|
||||
foreach ($options['status'] as $status) {
|
||||
if (!empty($this->tasksCounts[$type][$scheduledIn][$status])) {
|
||||
$count += $this->tasksCounts[$type][$scheduledIn][$status];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<?php
|
||||
Reference in New Issue
Block a user