diff --git a/lib/Cron/CronHelper.php b/lib/Cron/CronHelper.php new file mode 100644 index 0000000000..9794b14f4e --- /dev/null +++ b/lib/Cron/CronHelper.php @@ -0,0 +1,67 @@ + '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.*?):(?P\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.')); + } +} \ No newline at end of file diff --git a/lib/Cron/Daemon.php b/lib/Cron/Daemon.php index c9b1a7b7e4..2b83b96405 100644 --- a/lib/Cron/Daemon.php +++ b/lib/Cron/Daemon.php @@ -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; + } } \ No newline at end of file diff --git a/lib/Cron/Supervisor.php b/lib/Cron/Supervisor.php index cc0aa3b4ec..9bda7ac52e 100644 --- a/lib/Cron/Supervisor.php +++ b/lib/Cron/Supervisor.php @@ -1,26 +1,24 @@ 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.*?):(?P\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) ) ); diff --git a/lib/Router/Cron.php b/lib/Router/Cron.php index b0a606d303..05a6c42d6b 100644 --- a/lib/Router/Cron.php +++ b/lib/Router/Cron.php @@ -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(