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' =>
|
'plugins' =>
|
||||||
array('core' => array(
|
array('core' => array(
|
||||||
'AuthCrypt' => array(),
|
'AuthCrypt' => array(),
|
||||||
'Cron' => array(),
|
'Cronish' => array(),
|
||||||
'LRDD' => array(),
|
'LRDD' => array(),
|
||||||
|
'OpportunisticQM' => array(),
|
||||||
'StrictTransportSecurity' => array(),
|
'StrictTransportSecurity' => array(),
|
||||||
),
|
),
|
||||||
'default' => array(
|
'default' => array(
|
||||||
|
|
|
@ -67,8 +67,8 @@ abstract class QueueManager extends IoManager
|
||||||
self::$qm = new UnQueueManager();
|
self::$qm = new UnQueueManager();
|
||||||
} else {
|
} else {
|
||||||
switch ($type) {
|
switch ($type) {
|
||||||
case 'cron':
|
case 'opportunistic':
|
||||||
self::$qm = new CronQueueManager();
|
self::$qm = new OpportunisticQueueManager();
|
||||||
break;
|
break;
|
||||||
case 'db':
|
case 'db':
|
||||||
self::$qm = new DBQueueManager();
|
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