diff --git a/lib/classes/task/scheduled_task.php b/lib/classes/task/scheduled_task.php index ed2fc03144c..9c525e5860d 100644 --- a/lib/classes/task/scheduled_task.php +++ b/lib/classes/task/scheduled_task.php @@ -31,6 +31,15 @@ namespace core\task; */ abstract class scheduled_task extends task_base { + /** Minimum minute value. */ + const MINUTEMIN = 0; + /** Maximum minute value. */ + const MINUTEMAX = 59; + /** Minimum hour value. */ + const HOURMIN = 0; + /** Maximum hour value. */ + const HOURMAX = 23; + /** @var string $hour - Pattern to work out the valid hours */ private $hour = '*'; @@ -88,10 +97,14 @@ abstract class scheduled_task extends task_base { } /** - * Setter for $minute. + * Setter for $minute. Accepts a special 'R' value + * which will be translated to a random minute. * @param string $minute */ public function set_minute($minute) { + if ($minute === 'R') { + $minute = mt_rand(self::HOURMIN, self::HOURMAX); + } $this->minute = $minute; } @@ -104,10 +117,14 @@ abstract class scheduled_task extends task_base { } /** - * Setter for $hour. + * Setter for $hour. Accepts a special 'R' value + * which will be translated to a random hour. * @param string $hour */ public function set_hour($hour) { + if ($hour === 'R') { + $hour = mt_rand(self::HOURMIN, self::HOURMAX); + } $this->hour = $hour; } @@ -302,8 +319,8 @@ abstract class scheduled_task extends task_base { public function get_next_scheduled_time() { global $CFG; - $validminutes = $this->eval_cron_field($this->minute, 0, 59); - $validhours = $this->eval_cron_field($this->hour, 0, 23); + $validminutes = $this->eval_cron_field($this->minute, self::MINUTEMIN, self::MINUTEMAX); + $validhours = $this->eval_cron_field($this->hour, self::HOURMIN, self::HOURMAX); // We need to change to the server timezone before using php date() functions. $origtz = date_default_timezone_get(); diff --git a/lib/tests/scheduled_task_test.php b/lib/tests/scheduled_task_test.php index bb81535d0a4..599c5010082 100644 --- a/lib/tests/scheduled_task_test.php +++ b/lib/tests/scheduled_task_test.php @@ -242,4 +242,35 @@ class core_scheduled_task_testcase extends advanced_testcase { $this->assertDebuggingCalled(); $this->assertNull($task); } + + /** + * Tests the use of 'R' syntax in time fields of tasks to get + * tasks be configured with a non-uniform time. + */ + public function test_random_time_specification() { + + // Testing non-deterministic things in a unit test is not really + // wise, so we just test the values have changed within allowed bounds. + $testclass = new \core\task\scheduled_test_task(); + + // The test task defaults to '*'. + $this->assertInternalType('string', $testclass->get_minute()); + $this->assertInternalType('string', $testclass->get_hour()); + + // Set a random value. + $testclass->set_minute('R'); + $testclass->set_hour('R'); + + // Verify the minute has changed within allowed bounds. + $minute = $testclass->get_minute(); + $this->assertInternalType('int', $minute); + $this->assertGreaterThanOrEqual(0, $minute); + $this->assertLessThanOrEqual(59, $minute); + + // Verify the hour has changed within allowed bounds. + $hour = $testclass->get_hour(); + $this->assertInternalType('int', $hour); + $this->assertGreaterThanOrEqual(0, $hour); + $this->assertLessThanOrEqual(23, $hour); + } } diff --git a/lib/upgrade.txt b/lib/upgrade.txt index acf6e019cdc..339eebe13f6 100644 --- a/lib/upgrade.txt +++ b/lib/upgrade.txt @@ -13,6 +13,9 @@ information provided here is intended especially for developers. * New function cm_info::create($cm) can be used when you need a cm_info object, but have a $cm which might only be a standard database record. * $CFG->enablegroupmembersonly no longer exists. +* Scheduled tasks have gained support for syntax to introduce variability when a + task will run across installs. When a when hour or minute are defined as 'R' + they will be installed with a random hour/minute value. DEPRECATIONS: * completion_info->get_incomplete_criteria() is deprecated and will be removed in Moodle 3.0.