Cron split into Cronish and OpportunisticQM
/main/cron changed to /main/runqueue The key-required functionality is not throughly tested yet.
This commit is contained in:
parent
0cd93c2761
commit
9400795a5f
|
@ -294,8 +294,9 @@ $default =
|
|||
'plugins' =>
|
||||
array('core' => array(
|
||||
'AuthCrypt' => array(),
|
||||
'Cron' => array(),
|
||||
'Cronish' => array(),
|
||||
'LRDD' => array(),
|
||||
'OpportunisticQM' => array(),
|
||||
'StrictTransportSecurity' => array(),
|
||||
),
|
||||
'default' => array(
|
||||
|
|
|
@ -67,8 +67,8 @@ abstract class QueueManager extends IoManager
|
|||
self::$qm = new UnQueueManager();
|
||||
} else {
|
||||
switch ($type) {
|
||||
case 'cron':
|
||||
self::$qm = new CronQueueManager();
|
||||
case 'opportunistic':
|
||||
self::$qm = new OpportunisticQueueManager();
|
||||
break;
|
||||
case 'db':
|
||||
self::$qm = new DBQueueManager();
|
||||
|
|
42
plugins/Cronish/CronishPlugin.php
Normal file
42
plugins/Cronish/CronishPlugin.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
class CronishPlugin extends Plugin {
|
||||
public function onCronHourly()
|
||||
{
|
||||
common_debug('CRON: Running hourly cron job!');
|
||||
}
|
||||
|
||||
public function onCronDaily()
|
||||
{
|
||||
common_debug('CRON: Running daily cron job!');
|
||||
}
|
||||
|
||||
public function onCronWeekly()
|
||||
{
|
||||
common_debug('CRON: Running weekly cron job!');
|
||||
}
|
||||
|
||||
/**
|
||||
* When the page has finished rendering, let's do some cron jobs
|
||||
* if we have the time.
|
||||
*/
|
||||
public function onEndActionExecute($status, Action $action)
|
||||
{
|
||||
$cron = new Cronish();
|
||||
$cron->callTimedEvents();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onPluginVersion(&$versions)
|
||||
{
|
||||
$versions[] = array('name' => 'Cronish',
|
||||
'version' => GNUSOCIAL_VERSION,
|
||||
'author' => 'Mikael Nordfeldth',
|
||||
'homepage' => 'http://www.gnu.org/software/social/',
|
||||
'description' =>
|
||||
// TRANS: Plugin description.
|
||||
_m('Cronish plugin that executes events on a near-hour/day/week basis.'));
|
||||
return true;
|
||||
}
|
||||
}
|
58
plugins/Cronish/lib/cronish.php
Normal file
58
plugins/Cronish/lib/cronish.php
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
/**
|
||||
* GNU social cron-on-visit class
|
||||
*
|
||||
* Keeps track, through Config dataobject class, of relative time since the
|
||||
* last run in order to to run event handlers with certain intervals.
|
||||
*
|
||||
* @category Cron
|
||||
* @package GNUsocial
|
||||
* @author Mikael Nordfeldth <mmn@hethane.se>
|
||||
* @copyright 2013 Free Software Foundation, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class Cronish
|
||||
{
|
||||
/**
|
||||
* Will call events as close as it gets to one hour. Event handlers
|
||||
* which use this MUST be as quick as possible, maybe only adding a
|
||||
* queue item to be handled later or something. Otherwise execution
|
||||
* will timeout for PHP - or at least cause unnecessary delays for
|
||||
* the unlucky user who visits the site exactly at one of these events.
|
||||
*/
|
||||
public function callTimedEvents()
|
||||
{
|
||||
$timers = array('hourly' => 3600,
|
||||
'daily' => 86400,
|
||||
'weekly' => 604800);
|
||||
|
||||
foreach($timers as $name=>$interval) {
|
||||
$run = false;
|
||||
|
||||
$lastrun = new Config();
|
||||
$lastrun->section = 'cron';
|
||||
$lastrun->setting = 'last_' . $name;
|
||||
$found = $lastrun->find(true);
|
||||
|
||||
if (!$found) {
|
||||
$lastrun->value = time();
|
||||
if ($lastrun->insert() === false) {
|
||||
common_log(LOG_WARNING, "Could not save 'cron' setting '{$name}'");
|
||||
continue;
|
||||
}
|
||||
$run = true;
|
||||
} elseif ($lastrun->value < time() - $interval) {
|
||||
$orig = clone($lastrun);
|
||||
$lastrun->value = time();
|
||||
$lastrun->update($orig);
|
||||
$run = true;
|
||||
}
|
||||
|
||||
if ($run === true) {
|
||||
// such as CronHourly, CronDaily, CronWeekly
|
||||
Event::handle('Cron' . ucfirst($name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
46
plugins/OpportunisticQM/OpportunisticQMPlugin.php
Normal file
46
plugins/OpportunisticQM/OpportunisticQMPlugin.php
Normal file
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
class OpportunisticQMPlugin extends Plugin {
|
||||
public $qmkey = false;
|
||||
public $secs_per_action = 1; // total seconds to run script per action
|
||||
public $rel_to_pageload = true; // relative to pageload or queue start
|
||||
|
||||
public function onRouterInitialized($m)
|
||||
{
|
||||
$m->connect('main/runqueue', array('action' => 'runqueue'));
|
||||
}
|
||||
|
||||
/**
|
||||
* When the page has finished rendering, let's do some cron jobs
|
||||
* if we have the time.
|
||||
*/
|
||||
public function onEndActionExecute($status, Action $action)
|
||||
{
|
||||
if ($action instanceof RunqueueAction) {
|
||||
return true;
|
||||
}
|
||||
|
||||
global $_startTime;
|
||||
|
||||
$args = array(
|
||||
'qmkey' => common_config('opportunisticqm', 'qmkey'),
|
||||
'max_execution_time' => $this->secs_per_action,
|
||||
'started_at' => $this->rel_to_pageload ? $_startTime : null,
|
||||
);
|
||||
$qm = new OpportunisticQueueManager($args);
|
||||
$qm->runQueue();
|
||||
return true;
|
||||
}
|
||||
|
||||
public function onPluginVersion(&$versions)
|
||||
{
|
||||
$versions[] = array('name' => 'OpportunisticQM',
|
||||
'version' => GNUSOCIAL_VERSION,
|
||||
'author' => 'Mikael Nordfeldth',
|
||||
'homepage' => 'http://www.gnu.org/software/social/',
|
||||
'description' =>
|
||||
// TRANS: Plugin description.
|
||||
_m('Opportunistic queue manager plugin for background processing.'));
|
||||
return true;
|
||||
}
|
||||
}
|
61
plugins/OpportunisticQM/actions/runqueue.php
Normal file
61
plugins/OpportunisticQM/actions/runqueue.php
Normal file
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
/*
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2008, 2009, StatusNet, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class RunqueueAction extends Action
|
||||
{
|
||||
protected $qm = null;
|
||||
|
||||
protected function prepare(array $args=array())
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$args = array();
|
||||
|
||||
foreach (array('qmkey') as $key) {
|
||||
if ($this->arg($key) !== null) {
|
||||
$args[$key] = $this->arg($key);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$this->qm = new OpportunisticQueueManager($args);
|
||||
} catch (RunQueueBadKeyException $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
header('Content-type: text/plain; charset=utf-8');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function handle() {
|
||||
// We don't need any of the parent functionality from parent::handle() here.
|
||||
|
||||
// runQueue is a loop that works until limits have passed or there is no more work
|
||||
if ($this->qm->runQueue() === true) {
|
||||
// We don't have any more work
|
||||
$this->text('0');
|
||||
} else {
|
||||
// There were still items left in queue when we aborted
|
||||
$this->text('1');
|
||||
}
|
||||
}
|
||||
}
|
102
plugins/OpportunisticQM/lib/opportunisticqueuemanager.php
Normal file
102
plugins/OpportunisticQM/lib/opportunisticqueuemanager.php
Normal file
|
@ -0,0 +1,102 @@
|
|||
<?php
|
||||
/**
|
||||
* GNU social queue-manager-on-visit class
|
||||
*
|
||||
* Will run events for a certain time, or until finished.
|
||||
*
|
||||
* Configure remote key if wanted with $config['opportunisticqm']['qmkey'] and
|
||||
* use with /main/runqueue?qmkey=abc123
|
||||
*
|
||||
* @category Cron
|
||||
* @package GNUsocial
|
||||
* @author Mikael Nordfeldth <mmn@hethane.se>
|
||||
* @copyright 2013 Free Software Foundation, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class OpportunisticQueueManager extends DBQueueManager
|
||||
{
|
||||
protected $qmkey = false;
|
||||
protected $max_execution_time = null;
|
||||
protected $max_queue_items = null;
|
||||
|
||||
protected $started_at = null;
|
||||
protected $handled_items = 0;
|
||||
|
||||
const MAXEXECTIME = 30; // typically just used for the /main/cron action
|
||||
|
||||
public function __construct(array $args=array()) {
|
||||
foreach (get_class_vars(get_class($this)) as $key=>$val) {
|
||||
if (array_key_exists($key, $args)) {
|
||||
$this->$key = $args[$key];
|
||||
}
|
||||
}
|
||||
$this->verifyKey();
|
||||
|
||||
if ($this->started_at === null) {
|
||||
$this->started_at = time();
|
||||
}
|
||||
|
||||
if ($this->max_execution_time === null) {
|
||||
$this->max_execution_time = ini_get('max_execution_time') ?: self::MAXEXECTIME;
|
||||
}
|
||||
|
||||
return parent::__construct();
|
||||
}
|
||||
|
||||
protected function verifyKey()
|
||||
{
|
||||
if ($this->qmkey !== common_config('opportunisticqm', 'qmkey')) {
|
||||
throw new RunQueueBadKeyException($this->qmkey);
|
||||
}
|
||||
}
|
||||
|
||||
public function canContinue()
|
||||
{
|
||||
$time_passed = time() - $this->started_at;
|
||||
|
||||
// Only continue if limit values are sane
|
||||
if ($time_passed <= 0 && (!is_null($this->max_queue_items) && $this->max_queue_items <= 0)) {
|
||||
return false;
|
||||
}
|
||||
// If too much time has passed, stop
|
||||
if ($time_passed >= $this->max_execution_time) {
|
||||
return false;
|
||||
}
|
||||
// If we have a max-item-limit, check if it has been passed
|
||||
if (!is_null($this->max_queue_items) && $this->handled_items >= $this->max_queue_items) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function poll()
|
||||
{
|
||||
$this->handled_items++;
|
||||
if (!parent::poll()) {
|
||||
throw new RunQueueOutOfWorkException();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes care of running through the queue items, returning when
|
||||
* the limits setup in __construct are met.
|
||||
*
|
||||
* @return true on workqueue finished, false if there are still items in the queue
|
||||
*/
|
||||
public function runQueue()
|
||||
{
|
||||
while ($this->canContinue()) {
|
||||
try {
|
||||
$this->poll();
|
||||
} catch (RunQueueOutOfWorkException $e) {
|
||||
common_debug('Opportunistic queue manager finished.');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
common_debug('Opportunistic queue manager passed execution time/item handling limit without being out of work.');
|
||||
return false;
|
||||
}
|
||||
}
|
39
plugins/OpportunisticQM/lib/runqueuebadkeyexception.php
Normal file
39
plugins/OpportunisticQM/lib/runqueuebadkeyexception.php
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
/**
|
||||
* Class for the GNU social cron exception when a bad key is used
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category Exception
|
||||
* @package GNUsocial
|
||||
* @author Mikael Nordfeldth <mmn@hethane.se>
|
||||
* @copyright 2013 Free Software Foundation, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class RunQueueBadKeyException extends ClientException
|
||||
{
|
||||
public $qmkey;
|
||||
|
||||
public function __construct($qmkey)
|
||||
{
|
||||
$this->qmkey = $qmkey;
|
||||
parent::__construct(_('Bad queue manager key was used.'));
|
||||
}
|
||||
}
|
36
plugins/OpportunisticQM/lib/runqueueoutofworkexception.php
Normal file
36
plugins/OpportunisticQM/lib/runqueueoutofworkexception.php
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
/**
|
||||
* Class for the GNU social cron exception when there is no more work to be done
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category Exception
|
||||
* @package GNUsocial
|
||||
* @author Mikael Nordfeldth <mmn@hethane.se>
|
||||
* @copyright 2013 Free Software Foundation, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
|
||||
* @link http://www.gnu.org/software/social/
|
||||
*/
|
||||
|
||||
if (!defined('GNUSOCIAL')) { exit(1); }
|
||||
|
||||
class RunQueueOutOfWorkException extends ServerException
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(_('Opportunistic queue manager is out of work (no more items).'));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user