- Refactors and fixes issues identified during code review

This commit is contained in:
Vlad
2016-01-29 13:08:06 -05:00
parent d4d575cda4
commit 32f8f07602
4 changed files with 95 additions and 89 deletions

67
lib/Cron/CronHelper.php Normal file
View 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&section=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.'));
}
}

View File

@ -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&section=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;
}
}

View File

@ -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&section=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)
)
);

View File

@ -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(