]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
Cron split into Cronish and OpportunisticQM
authorMikael Nordfeldth <mmn@hethane.se>
Wed, 20 Nov 2013 20:20:42 +0000 (21:20 +0100)
committerMikael Nordfeldth <mmn@hethane.se>
Wed, 20 Nov 2013 20:20:42 +0000 (21:20 +0100)
/main/cron changed to /main/runqueue

The key-required functionality is not throughly tested yet.

lib/default.php
lib/queuemanager.php
plugins/Cronish/CronishPlugin.php [new file with mode: 0644]
plugins/Cronish/lib/cronish.php [new file with mode: 0644]
plugins/OpportunisticQM/OpportunisticQMPlugin.php [new file with mode: 0644]
plugins/OpportunisticQM/actions/runqueue.php [new file with mode: 0644]
plugins/OpportunisticQM/lib/opportunisticqueuemanager.php [new file with mode: 0644]
plugins/OpportunisticQM/lib/runqueuebadkeyexception.php [new file with mode: 0644]
plugins/OpportunisticQM/lib/runqueueoutofworkexception.php [new file with mode: 0644]

index 5ce0f450618de6d046077fe7599d6397b07afd81..27c26c15a2a0590b7b5cbdda8be555bb305a94eb 100644 (file)
@@ -294,8 +294,9 @@ $default =
         'plugins' =>
         array('core' => array(
                             'AuthCrypt' => array(),
-                            'Cron' => array(),
+                            'Cronish' => array(),
                             'LRDD' => array(),
+                            'OpportunisticQM' => array(),
                             'StrictTransportSecurity' => array(),
                         ),
               'default' => array(
index c8409df2e489933ec74b17a493f7cbcc969d7f1b..1fb6c3eb45db88db6ac7ccff48f6e08de1936efa 100644 (file)
@@ -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();
diff --git a/plugins/Cronish/CronishPlugin.php b/plugins/Cronish/CronishPlugin.php
new file mode 100644 (file)
index 0000000..b0c0095
--- /dev/null
@@ -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;
+    }
+}
diff --git a/plugins/Cronish/lib/cronish.php b/plugins/Cronish/lib/cronish.php
new file mode 100644 (file)
index 0000000..c7d79ee
--- /dev/null
@@ -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));
+            }
+        }
+    }
+}
diff --git a/plugins/OpportunisticQM/OpportunisticQMPlugin.php b/plugins/OpportunisticQM/OpportunisticQMPlugin.php
new file mode 100644 (file)
index 0000000..89bd15a
--- /dev/null
@@ -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;
+    }
+}
diff --git a/plugins/OpportunisticQM/actions/runqueue.php b/plugins/OpportunisticQM/actions/runqueue.php
new file mode 100644 (file)
index 0000000..e6ce5b8
--- /dev/null
@@ -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');
+        }
+    }
+}
diff --git a/plugins/OpportunisticQM/lib/opportunisticqueuemanager.php b/plugins/OpportunisticQM/lib/opportunisticqueuemanager.php
new file mode 100644 (file)
index 0000000..5b09be8
--- /dev/null
@@ -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;
+    }
+}
diff --git a/plugins/OpportunisticQM/lib/runqueuebadkeyexception.php b/plugins/OpportunisticQM/lib/runqueuebadkeyexception.php
new file mode 100644 (file)
index 0000000..1e17b5f
--- /dev/null
@@ -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.'));
+    }
+}
diff --git a/plugins/OpportunisticQM/lib/runqueueoutofworkexception.php b/plugins/OpportunisticQM/lib/runqueueoutofworkexception.php
new file mode 100644 (file)
index 0000000..f81aeda
--- /dev/null
@@ -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).'));
+    }
+}