MDL-44733 add support for disabling of scheduled tasks

This commit is contained in:
Petr Škoda 2014-03-24 11:34:31 +08:00 committed by Petr Škoda
parent ad32dda90c
commit 0a5aa65b53
14 changed files with 182 additions and 64 deletions

View File

@ -34,42 +34,44 @@ require_once($CFG->libdir.'/formslib.php');
*/
class tool_task_edit_scheduled_task_form extends moodleform {
public function definition() {
global $CFG;
$mform = $this->_form;
/** @var \core\task\scheduled_task $task */
$task = $this->_customdata;
$never = get_string('never');
$none = get_string('none');
$lastrun = $task->get_last_run_time() ? userdate($task->get_last_run_time()) : $never;
$nextrun = $task->get_next_run_time() ? userdate($task->get_next_run_time()) : $none;
$lastrun = $task->get_last_run_time() ? userdate($task->get_last_run_time()) : get_string('never');
$nextrun = $task->get_next_run_time();
if ($task->get_disabled()) {
$nextrun = get_string('disabled', 'tool_task');
} else if ($nextrun > time()) {
$nextrun = userdate($nextrun);
} else {
$nextrun = get_string('asap', 'tool_task');
}
$mform->addElement('static', 'lastrun', get_string('lastruntime', 'tool_task'), $lastrun);
$mform->addElement('static', 'nextrun', get_string('nextruntime', 'tool_task'), $nextrun);
$mform->addElement('text', 'minute', get_string('taskscheduleminute', 'tool_task'));
$mform->setType('minute', PARAM_RAW);
$mform->addHelpButton('minute', 'taskscheduleminute', 'tool_task');
$mform->setDefault('minute', $task->get_minute());
$mform->addElement('text', 'hour', get_string('taskschedulehour', 'tool_task'));
$mform->setType('hour', PARAM_RAW);
$mform->addHelpButton('hour', 'taskschedulehour', 'tool_task');
$mform->setDefault('hour', $task->get_hour());
$mform->addElement('text', 'day', get_string('taskscheduleday', 'tool_task'));
$mform->setType('day', PARAM_RAW);
$mform->addHelpButton('day', 'taskscheduleday', 'tool_task');
$mform->setDefault('day', $task->get_day());
$mform->addElement('text', 'month', get_string('taskschedulemonth', 'tool_task'));
$mform->setType('month', PARAM_RAW);
$mform->addHelpButton('month', 'taskschedulemonth', 'tool_task');
$mform->setDefault('month', $task->get_month());
$mform->addElement('text', 'dayofweek', get_string('taskscheduledayofweek', 'tool_task'));
$mform->setType('dayofweek', PARAM_RAW);
$mform->addHelpButton('dayofweek', 'taskscheduledayofweek', 'tool_task');
$mform->setDefault('dayofweek', $task->get_day_of_week());
$mform->addElement('advcheckbox', 'disabled', get_string('disabled', 'tool_task'));
$mform->addHelpButton('disabled', 'disabled', 'tool_task');
$mform->addElement('advcheckbox', 'resettodefaults', get_string('resettasktodefaults', 'tool_task'));
$mform->addHelpButton('resettodefaults', 'resettasktodefaults', 'tool_task');
@ -79,12 +81,16 @@ class tool_task_edit_scheduled_task_form extends moodleform {
$mform->disabledIf('day', 'resettodefaults', 'checked');
$mform->disabledIf('dayofweek', 'resettodefaults', 'checked');
$mform->disabledIf('month', 'resettodefaults', 'checked');
$mform->disabledIf('disabled', 'resettodefaults', 'checked');
$mform->addElement('hidden', 'task', get_class($task));
$mform->setType('task', PARAM_RAW);
$mform->addElement('hidden', 'action', 'edit');
$mform->setType('action', PARAM_ALPHANUMEXT);
$this->add_action_buttons(true, get_string('savechanges'));
// Do not use defaults for existing values, the set_data() is the correct way.
$this->set_data(\core\task\manager::record_from_scheduled_task($task));
}
}

View File

@ -70,7 +70,15 @@ if ($options['list']) {
. $task->get_day_of_week() . ' '
. $task->get_month() . ' '
. $task->get_day_of_week();
$nextrun = $task->get_next_run_time() ? userdate($task->get_next_run_time(), $shorttime) : 'asap';
$nextrun = $task->get_next_run_time();
if ($task->get_disabled()) {
$nextrun = get_string('disabled', 'tool_task');
} else if ($nextrun > time()) {
$nextrun = userdate($nextrun);
} else {
$nextrun = get_string('asap', 'tool_task');
}
echo str_pad($class, 50, ' ') . ' ' . str_pad($schedule, 17, ' ') . ' ' . $nextrun . "\n";
}

View File

@ -22,10 +22,13 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['asap'] = 'ASAP';
$string['blocking'] = 'Blocking';
$string['component'] = 'Component';
$string['corecomponent'] = 'Core';
$string['default'] = 'Default';
$string['disabled'] = 'Disabled';
$string['disabled_help'] = 'Disabled scheduled tasks are not executed from cron, however they can still be executed manually via the CLI tool.';
$string['edittaskschedule'] = 'Edit task schedule: {$a}';
$string['faildelay'] = 'Fail delay';
$string['lastruntime'] = 'Last run';

View File

@ -57,11 +57,19 @@ class tool_task_renderer extends plugin_renderer_base {
$yes = get_string('yes');
$no = get_string('no');
$never = get_string('never');
$now = get_string('now');
$asap = get_string('asap', 'tool_task');
$disabled = get_string('disabled', 'tool_task');
foreach ($tasks as $task) {
$customised = $task->is_customised() ? $no : $yes;
$lastrun = $task->get_last_run_time() ? userdate($task->get_last_run_time()) : $never;
$nextrun = $task->get_next_run_time() ? userdate($task->get_next_run_time()) : $now;
$nextrun = $task->get_next_run_time();
if ($task->get_disabled()) {
$nextrun = $disabled;
} else if ($nextrun > time()) {
$nextrun = userdate($nextrun);
} else {
$nextrun = $asap;
}
$configureurl = new moodle_url('/admin/tool/task/scheduledtasks.php', array('action'=>'edit', 'task' => get_class($task)));
$editlink = $this->action_icon($configureurl, new pix_icon('t/edit', get_string('edittaskschedule', 'tool_task', $task->get_name())));

View File

@ -73,6 +73,7 @@ if ($mform && $mform->is_cancelled()) {
$task->set_month($defaulttask->get_month());
$task->set_day_of_week($defaulttask->get_day_of_week());
$task->set_day($defaulttask->get_day());
$task->set_disabled($defaulttask->get_disabled());
$task->set_customised(false);
} else {
$task->set_minute($data->minute);
@ -80,6 +81,7 @@ if ($mform && $mform->is_cancelled()) {
$task->set_month($data->month);
$task->set_day_of_week($data->dayofweek);
$task->set_day($data->day);
$task->set_disabled($data->disabled);
$task->set_customised(true);
}

View File

@ -198,6 +198,7 @@ class manager {
$record->day = $task->get_day();
$record->dayofweek = $task->get_day_of_week();
$record->month = $task->get_month();
$record->disabled = $task->get_disabled();
return $record;
}
@ -306,6 +307,9 @@ class manager {
if (isset($record->faildelay)) {
$task->set_fail_delay($record->faildelay);
}
if (isset($record->disabled)) {
$task->set_disabled($record->disabled);
}
return $task;
}
@ -446,7 +450,9 @@ class manager {
throw new \moodle_exception('locktimeout');
}
$where = '(lastruntime IS NULL OR lastruntime < :timestart1) AND (nextruntime IS NULL OR nextruntime < :timestart2)';
$where = "(lastruntime IS NULL OR lastruntime < :timestart1)
AND (nextruntime IS NULL OR nextruntime < :timestart2)
AND disabled = 0";
$params = array('timestart1' => $timestart, 'timestart2' => $timestart);
$records = $DB->get_records_select('task_scheduled', $where, $params);

View File

@ -52,6 +52,9 @@ abstract class scheduled_task extends task_base {
/** @var boolean $customised - Has this task been changed from it's default schedule? */
private $customised = false;
/** @var int $disabled - Is this task disabled in cron? */
private $disabled = false;
/**
* Get the last run time for this scheduled task.
* @return int
@ -164,6 +167,22 @@ abstract class scheduled_task extends task_base {
return $this->dayofweek;
}
/**
* Setter for $disabled.
* @param bool $disabled
*/
public function set_disabled($disabled) {
$this->disabled = (bool)$disabled;
}
/**
* Getter for $disabled.
* @return bool
*/
public function get_disabled() {
return $this->disabled;
}
/**
* Take a cron field definition and return an array of valid numbers with the range min-max.
*

View File

@ -75,8 +75,8 @@ abstract class task_base {
}
/**
* Get the last run time for this task.
* @return int
* Get the next run time for this task.
* @return int timestamp
*/
public function get_next_run_time() {
return $this->nextruntime;

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="lib/db" VERSION="20140213" COMMENT="XMLDB file for core Moodle tables"
<XMLDB PATH="lib/db" VERSION="20140324" COMMENT="XMLDB file for core Moodle tables"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../lib/xmldb/xmldb.xsd"
>
@ -1465,7 +1465,7 @@
<FIELD NAME="credit" TYPE="number" LENGTH="15" NOTNULL="true" SEQUENCE="false" DECIMALS="5"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
</KEYS>
</TABLE>
<TABLE NAME="question_response_count" COMMENT="Count for each responses for each try at a question.">
@ -1476,9 +1476,9 @@
<FIELD NAME="rcount" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
<KEY NAME="analysisid" TYPE="foreign" FIELDS="analysisid" REFTABLE="question_response_analysis" REFFIELDS="id"/>
</KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
<KEY NAME="analysisid" TYPE="foreign" FIELDS="analysisid" REFTABLE="question_response_analysis" REFFIELDS="id"/>
</KEYS>
</TABLE>
<TABLE NAME="mnet_application" COMMENT="Information about applications on remote hosts">
<FIELDS>
@ -3074,6 +3074,7 @@
<FIELD NAME="dayofweek" TYPE="char" LENGTH="25" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="faildelay" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false"/>
<FIELD NAME="customised" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Used on upgrades to prevent overwriting custom schedules."/>
<FIELD NAME="disabled" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="1 means do not run from cron"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>

View File

@ -3085,6 +3085,7 @@ function xmldb_main_upgrade($oldversion) {
$table->add_field('dayofweek', XMLDB_TYPE_CHAR, '25', null, XMLDB_NOTNULL, null, null);
$table->add_field('faildelay', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
$table->add_field('customised', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0');
$table->add_field('disabled', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0');
// Adding keys to table task_scheduled.
$table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
@ -3331,5 +3332,20 @@ function xmldb_main_upgrade($oldversion) {
upgrade_main_savepoint(true, 2014032600.02);
}
if ($oldversion < 2014032700.01) {
// Define field disabled to be added to task_scheduled.
$table = new xmldb_table('task_scheduled');
$field = new xmldb_field('disabled', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'customised');
// Conditionally launch add field disabled.
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
// Main savepoint reached.
upgrade_main_savepoint(true, 2014032700.01);
}
return true;
}

View File

@ -15,7 +15,7 @@
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file contains the unittests for the css optimiser in csslib.php
* This file contains the unittests for adhock tasks.
*
* @package core
* @category phpunit
@ -24,6 +24,7 @@
*/
defined('MOODLE_INTERNAL') || die();
require_once(__DIR__ . '/fixtures/task_fixtures.php');
/**
@ -34,14 +35,12 @@ defined('MOODLE_INTERNAL') || die();
* @copyright 2013 Damyon Wiese
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class adhoc_task_testcase extends advanced_testcase {
class core_adhoc_task_testcase extends advanced_testcase {
public function test_get_next_adhoc_task() {
global $DB;
$this->resetAfterTest(true);
// Create an adhoc task.
$task = new testable_adhoc_task();
$task = new \core\task\adhoc_test_task();
// Queue it.
$task = \core\task\manager::queue_adhoc_task($task);
@ -69,8 +68,3 @@ class adhoc_task_testcase extends advanced_testcase {
$this->assertNull($task);
}
}
class testable_adhoc_task extends \core\task\adhoc_task {
public function execute() {
}
}

59
lib/tests/fixtures/task_fixtures.php vendored Normal file
View File

@ -0,0 +1,59 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Fixtures for task tests.
*
* @package core
* @category phpunit
* @copyright 2014 Petr Skoda
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core\task;
defined('MOODLE_INTERNAL') || die();
class adhoc_test_task extends \core\task\adhoc_task {
public function execute() {
}
}
class scheduled_test_task extends \core\task\scheduled_task {
public function get_name() {
return "Test task";
}
public function execute() {
}
}
class scheduled_test2_task extends \core\task\scheduled_task {
public function get_name() {
return "Test task 2";
}
public function execute() {
}
}
class scheduled_test3_task extends \core\task\scheduled_task {
public function get_name() {
return "Test task 3";
}
public function execute() {
}
}

View File

@ -15,7 +15,7 @@
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file contains the unittests for the css optimiser in csslib.php
* This file contains the unittests for scheduled tasks.
*
* @package core
* @category phpunit
@ -24,7 +24,7 @@
*/
defined('MOODLE_INTERNAL') || die();
require_once(__DIR__ . '/fixtures/task_fixtures.php');
/**
* Test class for scheduled task.
@ -34,13 +34,13 @@ defined('MOODLE_INTERNAL') || die();
* @copyright 2013 Damyon Wiese
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class scheduled_task_testcase extends advanced_testcase {
class core_scheduled_task_testcase extends advanced_testcase {
/**
* Test the cron scheduling method
*/
public function test_eval_cron_field() {
$testclass = new testable_scheduled_task();
$testclass = new \core\task\scheduled_test_task();
$this->assertEquals(20, count($testclass->eval_cron_field('*/3', 0, 59)));
$this->assertEquals(31, count($testclass->eval_cron_field('1,*/2', 0, 59)));
@ -52,7 +52,7 @@ class scheduled_task_testcase extends advanced_testcase {
public function test_get_next_scheduled_time() {
// Test job run at 1 am.
$testclass = new testable_scheduled_task();
$testclass = new \core\task\scheduled_test_task();
// All fields default to '*'.
$testclass->set_hour('1');
@ -68,8 +68,13 @@ class scheduled_task_testcase extends advanced_testcase {
$this->assertEquals($oneam, $nexttime, 'Next scheduled time is 1am.');
// Disabled flag does not affect next time.
$testclass->set_disabled(true);
$nexttime = $testclass->get_next_scheduled_time();
$this->assertEquals($oneam, $nexttime, 'Next scheduled time is 1am.');
// Now test for job run every 10 minutes.
$testclass = new testable_scheduled_task();
$testclass = new \core\task\scheduled_test_task();
// All fields default to '*'.
$testclass->set_minute('*/10');
@ -80,6 +85,11 @@ class scheduled_task_testcase extends advanced_testcase {
$nexttenminutes = mktime(date('H'), $minutes, 0);
$this->assertEquals($nexttenminutes, $nexttime, 'Next scheduled time is in 10 minutes.');
// Disabled flag does not affect next time.
$testclass->set_disabled(true);
$nexttime = $testclass->get_next_scheduled_time();
$this->assertEquals($nexttenminutes, $nexttime, 'Next scheduled time is in 10 minutes.');
}
public function test_timezones() {
@ -103,7 +113,7 @@ class scheduled_task_testcase extends advanced_testcase {
// GMT-04:30.
$CFG->timezone = 'America/Caracas';
$testclass = new testable_scheduled_task();
$testclass = new \core\task\scheduled_test_task();
// Scheduled tasks should always use servertime - so this is 03:30 GMT.
$testclass->set_hour('1');
@ -142,23 +152,28 @@ class scheduled_task_testcase extends advanced_testcase {
$record->day = '*';
$record->month = '*';
$record->component = 'test_scheduled_task';
$record->classname = '\\testable_scheduled_task';
$record->classname = '\core\task\scheduled_test_task';
$DB->insert_record('task_scheduled', $record);
// And another one to test failures.
$record->classname = '\\testable_scheduled_task2';
$record->classname = '\core\task\scheduled_test2_task';
$DB->insert_record('task_scheduled', $record);
// And disabled test.
$record->classname = '\core\task\scheduled_test3_task';
$record->disabled = 1;
$DB->insert_record('task_scheduled', $record);
$now = time();
// Should get handed the first task.
$task = \core\task\manager::get_next_scheduled_task($now);
$this->assertNotNull($task);
$this->assertInstanceOf('\core\task\scheduled_test_task', $task);
$task->execute();
\core\task\manager::scheduled_task_complete($task);
// Should get handed the second task.
$task = \core\task\manager::get_next_scheduled_task($now);
$this->assertNotNull($task);
$this->assertInstanceOf('\core\task\scheduled_test2_task', $task);
$task->execute();
\core\task\manager::scheduled_task_failed($task);
@ -168,7 +183,7 @@ class scheduled_task_testcase extends advanced_testcase {
// Should get the second task (retry after delay).
$task = \core\task\manager::get_next_scheduled_task($now + 120);
$this->assertNotNull($task);
$this->assertInstanceOf('\core\task\scheduled_test2_task', $task);
$task->execute();
\core\task\manager::scheduled_task_complete($task);
@ -178,22 +193,3 @@ class scheduled_task_testcase extends advanced_testcase {
$this->assertNull($task);
}
}
class testable_scheduled_task extends \core\task\scheduled_task {
public function get_name() {
return "Test task";
}
public function execute() {
}
}
class testable_scheduled_task2 extends \core\task\scheduled_task {
public function get_name() {
return "Test task 2";
}
public function execute() {
}
}

View File

@ -29,7 +29,7 @@
defined('MOODLE_INTERNAL') || die();
$version = 2014032700.00; // YYYYMMDD = weekly release date of this DEV branch.
$version = 2014032700.01; // YYYYMMDD = weekly release date of this DEV branch.
// RR = release increments - 00 in DEV branches.
// .XX = incremental changes.