- Refactors and fixes issues identified during code review
This commit is contained in:
67
lib/Cron/CronHelper.php
Normal file
67
lib/Cron/CronHelper.php
Normal file
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
namespace MailPoet\Cron;
|
||||
|
||||
use MailPoet\Models\Setting;
|
||||
use MailPoet\Util\Security;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class CronHelper {
|
||||
static function createDaemon($token) {
|
||||
$daemon = array(
|
||||
'status' => 'starting',
|
||||
'counter' => 0,
|
||||
'token' => $token
|
||||
);
|
||||
self::saveDaemon($daemon);
|
||||
return $daemon;
|
||||
}
|
||||
|
||||
static function getDaemon() {
|
||||
return Setting::getValue('cron_daemon');
|
||||
}
|
||||
|
||||
static function saveDaemon($daemon) {
|
||||
$daemon['updated_at'] = time();
|
||||
return Setting::setValue(
|
||||
'cron_daemon',
|
||||
$daemon
|
||||
);
|
||||
}
|
||||
|
||||
static function createToken() {
|
||||
return Security::generateRandomString();
|
||||
}
|
||||
|
||||
static function accessDaemon($token) {
|
||||
$payload = serialize(array('token' => $token));
|
||||
$url = '/?mailpoet-api§ion=queue&action=run&request_payload=' .
|
||||
base64_encode($payload);
|
||||
$args = array(
|
||||
'timeout' => 1,
|
||||
'user-agent' => 'MailPoet (www.mailpoet.com) Cron'
|
||||
);
|
||||
$result = wp_remote_get(
|
||||
self::getSiteUrl() . $url,
|
||||
$args
|
||||
);
|
||||
return wp_remote_retrieve_body($result);
|
||||
}
|
||||
|
||||
private static function getSiteUrl() {
|
||||
// additional check for some sites running on a virtual machine or behind
|
||||
// proxy where there could be different ports (e.g., host:8080 => guest:80)
|
||||
|
||||
// if the site URL does not contain a port, return the URL
|
||||
if(!preg_match('!^https?://.*?:\d+!', site_url())) return site_url();
|
||||
preg_match('!://(?P<host>.*?):(?P<port>\d+)!', site_url(), $server);
|
||||
// connect to the URL with port
|
||||
$fp = @fsockopen($server['host'], $server['port'], $errno, $errstr, 1);
|
||||
if($fp) return site_url();
|
||||
// connect to the URL without port
|
||||
$fp = @fsockopen($server['host'], $server['port'], $errno, $errstr, 1);
|
||||
if($fp) return preg_replace('!(?=:\d+):\d+!', '$1', site_url());
|
||||
// throw an error if all connection attempts failed
|
||||
throw new \Exception(__('Site URL is unreachable.'));
|
||||
}
|
||||
}
|
@ -2,8 +2,6 @@
|
||||
namespace MailPoet\Cron;
|
||||
|
||||
use MailPoet\Cron\Workers\SendingQueue;
|
||||
use MailPoet\Models\Setting;
|
||||
use MailPoet\Util\Security;
|
||||
|
||||
require_once(ABSPATH . 'wp-includes/pluggable.php');
|
||||
|
||||
@ -13,13 +11,14 @@ class Daemon {
|
||||
public $daemon;
|
||||
public $request_payload;
|
||||
public $refreshed_token;
|
||||
public $timer;
|
||||
private $execution_time_limit = 30;
|
||||
private $timer;
|
||||
|
||||
function __construct($request_payload = array()) {
|
||||
set_time_limit(0);
|
||||
ignore_user_abort();
|
||||
$this->daemon = Supervisor::getDaemon();
|
||||
$this->token = Security::generateRandomString();
|
||||
$this->daemon = CronHelper::getDaemon();
|
||||
$this->token = CronHelper::createToken();
|
||||
$this->request_payload = $request_payload;
|
||||
$this->timer = microtime(true);
|
||||
}
|
||||
@ -41,13 +40,13 @@ class Daemon {
|
||||
} catch(Exception $e) {
|
||||
}
|
||||
$elapsed_time = microtime(true) - $this->timer;
|
||||
if($elapsed_time < 30) {
|
||||
sleep(30 - $elapsed_time);
|
||||
if($elapsed_time < $this->execution_time_limit) {
|
||||
sleep($this->execution_time_limit - $elapsed_time);
|
||||
}
|
||||
// after each execution, re-read daemon data in case its status has changed
|
||||
$daemon = Supervisor::getDaemon();
|
||||
$daemon = CronHelper::getDaemon();
|
||||
// if the token has changed, abort further processing
|
||||
if ($daemon['token'] !== $this->request_payload['token']) {
|
||||
if(!$daemon || $daemon['token'] !== $this->request_payload['token']) {
|
||||
exit;
|
||||
}
|
||||
$daemon['counter']++;
|
||||
@ -56,7 +55,7 @@ class Daemon {
|
||||
$daemon['status'] = 'started';
|
||||
}
|
||||
$daemon['token'] = $this->token;
|
||||
Supervisor::saveDaemon($daemon);
|
||||
CronHelper::saveDaemon($daemon);
|
||||
$this->callSelf();
|
||||
}
|
||||
|
||||
@ -64,21 +63,17 @@ class Daemon {
|
||||
if($daemon['status'] === 'stopped') exit;
|
||||
if($daemon['status'] === 'stopping') {
|
||||
$daemon['status'] = 'stopped';
|
||||
Supervisor::saveDaemon($daemon);
|
||||
CronHelper::saveDaemon($daemon);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
function callSelf() {
|
||||
$payload = serialize(array('token' => $this->token));
|
||||
Supervisor::accessRemoteUrl(
|
||||
'/?mailpoet-api§ion=queue&action=run&request_payload=' .
|
||||
base64_encode($payload)
|
||||
);
|
||||
exit;
|
||||
}
|
||||
|
||||
function abortWithError($message) {
|
||||
exit('[mailpoet_cron_error:' . base64_encode($message) . ']');
|
||||
}
|
||||
|
||||
function callSelf() {
|
||||
CronHelper::accessDaemon($this->token);
|
||||
exit;
|
||||
}
|
||||
}
|
@ -1,26 +1,24 @@
|
||||
<?php
|
||||
namespace MailPoet\Cron;
|
||||
|
||||
use MailPoet\Models\Setting;
|
||||
use MailPoet\Util\Security;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class Supervisor {
|
||||
public $daemon;
|
||||
public $token;
|
||||
public $force_run;
|
||||
private $timeout_limit = 40;
|
||||
|
||||
function __construct($force_run = false) {
|
||||
$this->daemon = self::getDaemon();
|
||||
$this->token = Security::generateRandomString();
|
||||
$this->daemon = CronHelper::getDaemon();
|
||||
$this->token = CronHelper::createToken();
|
||||
$this->force_run = $force_run;
|
||||
}
|
||||
|
||||
function checkDaemon() {
|
||||
$daemon = $this->daemon;
|
||||
if(!$daemon) {
|
||||
$daemon = $this->createDaemon();
|
||||
$daemon = CronHelper::createDaemon($this->token);
|
||||
return $this->runDaemon($daemon);
|
||||
}
|
||||
// if the daemon is stopped, return its status and do nothing
|
||||
@ -34,13 +32,13 @@ class Supervisor {
|
||||
$elapsed_time = time() - (int) $daemon['updated_at'];
|
||||
// if it's been less than 40 seconds since last execution and we're not
|
||||
// force-running the daemon, return its status and do nothing
|
||||
if($elapsed_time < 40 && !$this->force_run) {
|
||||
if($elapsed_time < $this->timeout_limit && !$this->force_run) {
|
||||
return $this->formatDaemonStatusMessage($daemon['status']);
|
||||
}
|
||||
// if it's been less than 40 seconds since last execution, we are
|
||||
// force-running the daemon and it's either being started or stopped,
|
||||
// return its status and do nothing
|
||||
elseif($elapsed_time < 40 &&
|
||||
elseif($elapsed_time < $this->timeout_limit &&
|
||||
$this->force_run &&
|
||||
in_array($daemon['status'], array(
|
||||
'stopping',
|
||||
@ -50,18 +48,14 @@ class Supervisor {
|
||||
return $this->formatDaemonStatusMessage($daemon['status']);
|
||||
}
|
||||
// re-create (restart) daemon
|
||||
$this->createDaemon();
|
||||
CronHelper::createDaemon($this->token);
|
||||
return $this->runDaemon();
|
||||
}
|
||||
|
||||
function runDaemon() {
|
||||
$payload = serialize(array('token' => $this->token));
|
||||
$request = self::accessRemoteUrl(
|
||||
'/?mailpoet-api§ion=queue&action=run&request_payload=' .
|
||||
base64_encode($payload)
|
||||
);
|
||||
$request = CronHelper::accessDaemon($this->token);
|
||||
preg_match('/\[(mailpoet_cron_error:.*?)\]/i', $request, $status);
|
||||
$daemon = self::getDaemon();
|
||||
$daemon = CronHelper::getDaemon();
|
||||
if(!empty($status) || !$daemon) {
|
||||
if(!$daemon) {
|
||||
$message = __('Daemon failed to run.');
|
||||
@ -77,62 +71,11 @@ class Supervisor {
|
||||
return $this->formatDaemonStatusMessage($daemon['status']);
|
||||
}
|
||||
|
||||
function createDaemon() {
|
||||
$daemon = array(
|
||||
'status' => 'starting',
|
||||
'counter' => 0,
|
||||
'token' => $this->token
|
||||
);
|
||||
self::saveDaemon($daemon);
|
||||
return $daemon;
|
||||
}
|
||||
|
||||
static function getDaemon() {
|
||||
return Setting::getValue('cron_daemon');
|
||||
}
|
||||
|
||||
static function saveDaemon($daemon_data) {
|
||||
$daemon_data['updated_at'] = time();
|
||||
return Setting::setValue(
|
||||
'cron_daemon',
|
||||
$daemon_data
|
||||
);
|
||||
}
|
||||
|
||||
static function accessRemoteUrl($url) {
|
||||
$args = array(
|
||||
'timeout' => 1,
|
||||
'user-agent' => 'MailPoet (www.mailpoet.com) Cron'
|
||||
);
|
||||
$result = wp_remote_get(
|
||||
self::getSiteUrl() . $url,
|
||||
$args
|
||||
);
|
||||
return wp_remote_retrieve_body($result);
|
||||
}
|
||||
|
||||
static function getSiteUrl() {
|
||||
// additional check for some sites running on a virtual machine or behind
|
||||
// proxy where there could be different ports (e.g., host:8080 => guest:80)
|
||||
|
||||
// if the site URL does not contain a port, return the URL
|
||||
if(!preg_match('!^https?://.*?:\d+!', site_url())) return site_url();
|
||||
preg_match('!://(?P<host>.*?):(?P<port>\d+)!', site_url(), $server);
|
||||
// connect to the URL with port
|
||||
$fp = @fsockopen($server['host'], $server['port'], $errno, $errstr, 1);
|
||||
if($fp) return site_url();
|
||||
// connect to the URL without port
|
||||
$fp = @fsockopen($server['host'], $server['port'], $errno, $errstr, 1);
|
||||
if($fp) return preg_replace('!(?=:\d+):\d+!', '$1', site_url());
|
||||
// throw an error if all connection attempts failed
|
||||
throw new \Exception(__('Site URL is unreachable.'));
|
||||
}
|
||||
|
||||
private function formatDaemonStatusMessage($status) {
|
||||
return $this->formatResultMessage(
|
||||
true,
|
||||
sprintf(
|
||||
__('Daemon is currently %.'),
|
||||
__('Daemon is currently %s.'),
|
||||
__($status)
|
||||
)
|
||||
);
|
||||
|
@ -2,6 +2,7 @@
|
||||
namespace MailPoet\Router;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use MailPoet\Cron\CronHelper;
|
||||
use MailPoet\Cron\Supervisor;
|
||||
use MailPoet\Models\Setting;
|
||||
|
||||
@ -14,12 +15,12 @@ class Cron {
|
||||
}
|
||||
|
||||
function stop() {
|
||||
$daemon = Supervisor::getDaemon();
|
||||
$daemon = CronHelper::getDaemon();
|
||||
if(!$daemon || $daemon['status'] !== 'started') {
|
||||
$result = false;
|
||||
} else {
|
||||
$daemon['status'] = 'stopping';
|
||||
Supervisor::saveDaemon($daemon);
|
||||
$result = CronHelper::saveDaemon($daemon);
|
||||
}
|
||||
wp_send_json(
|
||||
array(
|
||||
|
Reference in New Issue
Block a user