- Implements starting/stopping/pausing daemon

This commit is contained in:
MrCasual
2015-11-30 13:01:07 -05:00
parent daff3d5016
commit 8c847825fa
7 changed files with 111 additions and 71 deletions

View File

@@ -11,64 +11,89 @@ define(
MailPoet, MailPoet,
classNames classNames
) { ) {
var QueueDaemonControl = React.createClass({ var QueueControl = React.createClass({
getInitialState: function () { getInitialState: function () {
return (queueDaemon) ? { return (queueDaemon) ? queueDaemon : null;
status: queueDaemon.status,
timeSinceStart: queueDaemon.time_since_start,
timeSinceUpdate: queueDaemon.time_since_update,
counter: queueDaemon.counter
} : null;
}, },
getDaemonData: function () { getDaemonData: function () {
MailPoet.Ajax.post({ MailPoet.Ajax.post({
endpoint: 'queue', endpoint: 'queue',
action: 'getQueueStatus' action: 'getDaemonStatus'
}).done(function (response) { }).done(function (response) {
this.setState({ jQuery('.button-primary').removeClass('disabled');
status: response.status, if (!response) {
timeSinceStart: response.time_since_start, this.replaceState();
timeSinceUpdate: response.time_since_update, } else {
counter: response.counter, this.setState(response);
}); }
}.bind(this)); }.bind(this));
}, },
componentDidMount: function () { componentDidMount: function componentDidMount() {
this.getDaemonData; if (this.isMounted()) {
setInterval(this.getDaemonData, 5000); this.getDaemonData;
setInterval(this.getDaemonData, 5000);
}
},
controlDaemon: function (action) {
jQuery('.button-primary').addClass('disabled');
MailPoet.Ajax.post({
endpoint: 'queue',
action: 'controlDaemon',
data: {'action': action}
}).done(function (response) {
if (!response) {
this.replaceState();
} else {
this.setState(response);
}
}.bind(this));
}, },
render: function () { render: function () {
if (!this.state) { if (!this.state) {
return ( return
<div className="QueueControl"> <div>
Woops, daemon is not running ;\ Woops, daemon is not running ;\
</div> </div>
) }
switch (this.state.status) {
case 'started':
return (
<div>
<div>
Queue daemon is running.
<br/>
<br/>
It was started
<strong> {this.state.timeSinceStart} </strong> and last executed
<strong> {this.state.timeSinceUpdate} </strong> for a total of
<strong> {this.state.counter} </strong> times (once every 30 seconds, unless it was interrupted and restarted).
<br />
<br />
<a href="#" className="button-primary" onClick={this.controlDaemon.bind(null, 'stop')}>Stop</a>&nbsp;&nbsp;
<a href="#" className="button-primary" onClick={this.controlDaemon.bind(null, 'pause')}>Pause</a>
</div>
</div>
);
break;
case 'paused':
case 'stopped':
return (
<div>
Daemon is {this.state.status}
<br />
<br />
<a href="#" className="button-primary" onClick={this.controlDaemon.bind(null, 'start')}>Start</a>
</div>
)
break;
} }
return (
<div>
<div>
Queue is currently <b>{this.state.status}</b>.
<br/>
<br/>
It was started
<b> {this.state.timeSinceStart} </b> and was last executed
<b> {this.state.timeSinceUpdate} </b> for a total of
<b> {this.state.counter} </b> times (once every 30 seconds, unless it was interrupted and restarted).
<br />
</div>
<div>
</div>
</div>
);
} }
}); });
let container = document.getElementById('queue_container'); let container = document.getElementById('queue_container');
if (container) { if (container) {
ReactDOM.render( ReactDOM.render(
<QueueDaemonControl />, <QueueControl />,
container document.getElementById('queue_status')
) )
} }
} }

View File

@@ -16,13 +16,13 @@ class BootStrapMenu {
return ($this->daemon) ? return ($this->daemon) ?
array_merge( array_merge(
array( array(
'time_since_start' => 'timeSinceStart' =>
Carbon::createFromFormat( Carbon::createFromFormat(
'Y-m-d H:i:s', 'Y-m-d H:i:s',
$this->daemon->created_at, $this->daemon->created_at,
'UTC' 'UTC'
)->diffForHumans(), )->diffForHumans(),
'time_since_update' => 'timeSinceUpdate' =>
Carbon::createFromFormat( Carbon::createFromFormat(
'Y-m-d H:i:s', 'Y-m-d H:i:s',
$this->daemon->updated_at, $this->daemon->updated_at,

View File

@@ -28,7 +28,10 @@ class Daemon {
if(!$daemon) { if(!$daemon) {
$daemon = Setting::create(); $daemon = Setting::create();
$daemon->name = 'daemon'; $daemon->name = 'daemon';
$daemon->value = json_encode(array('status' => 'stopped')); $daemon->value = json_encode(
array(
'status' => 'stopped',
));
$daemon->save(); $daemon->save();
} }
if($daemonData['status'] !== 'started') { if($daemonData['status'] !== 'started') {
@@ -36,7 +39,7 @@ class Daemon {
$daemonData = array( $daemonData = array(
'status' => 'started', 'status' => 'started',
'token' => $this->refreshedToken, 'token' => $this->refreshedToken,
'counter' => ($daemonData['status'] === 'paused') ? 'counter' => $daemonData['status'] === 'paused' ?
$daemonData['counter'] : $daemonData['counter'] :
0 0
); );
@@ -67,7 +70,7 @@ class Daemon {
$worker = new Worker(); $worker = new Worker();
$worker->process(); $worker->process();
$elapsedTime = microtime(true) - $this->timer; $elapsedTime = microtime(true) - $this->timer;
if ($elapsedTime < 30) { if($elapsedTime < 30) {
sleep(30 - $elapsedTime); sleep(30 - $elapsedTime);
} }
@@ -90,11 +93,11 @@ class Daemon {
} }
function refreshToken() { function refreshToken() {
return Security::generateRandomString(5); return Security::generateRandomString();
} }
function manageSession($action) { function manageSession($action) {
switch ($action) { switch($action) {
case 'start': case 'start':
if(session_id()) { if(session_id()) {
session_write_close(); session_write_close();

View File

@@ -17,11 +17,11 @@ class Supervisor {
} }
function checkDaemon() { function checkDaemon() {
if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH'])) return;
if(!$this->daemon) { if(!$this->daemon) {
return $this->startDaemon(); return $this->startDaemon();
} else { } else {
if(!$this->forceStart && ($this->daemonData['status'] === 'paused' || if(!$this->forceStart && (
$this->daemonData['status'] === 'paused' ||
$this->daemonData['status'] === 'stopped' $this->daemonData['status'] === 'stopped'
) )
) { ) {
@@ -33,8 +33,13 @@ class Supervisor {
$this->daemon->updated_at, 'UTC' $this->daemon->updated_at, 'UTC'
); );
$timeSinceLastStart = $currentTime->diffInSeconds($lastUpdateTime); $timeSinceLastStart = $currentTime->diffInSeconds($lastUpdateTime);
if($timeSinceLastStart < 50) return; if(!$this->forceStart && $timeSinceLastStart < 50) return;
$this->daemonData['status'] = 'paused'; if(
($this->forceStart && $this->daemonData['status'] === 'paused') ||
!$this->forceStart
) {
$this->daemonData['status'] = 'paused';
}
$this->daemon->value = json_encode($this->daemonData); $this->daemon->value = json_encode($this->daemonData);
$this->daemon->save(); $this->daemon->save();
return $this->startDaemon(); return $this->startDaemon();

View File

@@ -1,26 +1,24 @@
<?php <?php
namespace MailPoet\Router; namespace MailPoet\Router;
use MailPoet\Models\Setting;
use MailPoet\Queue\Daemon; use MailPoet\Queue\Daemon;
use MailPoet\Queue\Supervisor; use MailPoet\Queue\Supervisor;
if(!defined('ABSPATH')) exit; if(!defined('ABSPATH')) exit;
class Queue { class Queue {
function start() { function controlDaemon($data) {
$supervisor = new Supervisor(); switch($data['action']) {
wp_send_json( case 'start':
array( $supervisor = new Supervisor($forceStart = true);
'result' => ($supervisor->checkDaemon($forceStart = true)) ? wp_send_json(
true : array(
false 'result' => $supervisor->checkDaemon() ?
) true :
); false
} )
);
function update($data) { break;
switch ($data['action']) {
case 'stop': case 'stop':
$status = 'stopped'; $status = 'stopped';
break; break;
@@ -43,9 +41,8 @@ class Queue {
); );
} }
function getQueueStatus() { function getDaemonStatus() {
$daemon = new \MailPoet\Queue\BootStrapMenu(); $daemon = new \MailPoet\Queue\BootStrapMenu();
wp_send_json($daemon->bootStrap()); wp_send_json($daemon->bootStrap());
} }
} }

View File

@@ -8,7 +8,14 @@ class Security {
return wp_create_nonce('mailpoet_token'); return wp_create_nonce('mailpoet_token');
} }
static function generateRandomString($length) { static function generateRandomString($length = 5) {
return substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, $length); // non-cryptographically strong random generator
return substr(
md5(
uniqid(
mt_rand(), true)
),
0,
(!is_int($length) || $length <= 5 || $length >= 32) ? 5 : $length);
} }
} }

View File

@@ -1,7 +1,10 @@
<% extends 'layout.html' %> <% extends 'layout.html' %>
<% block content %> <% block content %>
<div id="queue_container"></div> <div id="queue_container">
<div id="queue_status"></div>
<div id="queue_control"></div>
</div>
<script type="text/javascript"> <script type="text/javascript">
</script> </script>
<script> <script>