MDL-47221 task: allow 'random' time definitions
authorDan Poltawski <dan@moodle.com>
Sat, 27 Sep 2014 20:22:57 +0000 (21:22 +0100)
committerDan Poltawski <dan@moodle.com>
Sun, 5 Oct 2014 13:25:44 +0000 (14:25 +0100)
When working against external services it can be advantageous to not
have automated tasks all hit the service at the exact same time from
many different installations.

This change allows the use of 'R' in hour/minute fields of the scheduled
task definition so a task will be installed with a 'random' hour/minute
value for these sort of occasions.

Note that the task will be installed in the database with a defined
time, this simply randomises the time chosen when loading from the
definiton.

lib/classes/task/scheduled_task.php
lib/tests/scheduled_task_test.php
lib/upgrade.txt

index ed2fc03..9c525e5 100644 (file)
@@ -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();
index bb81535..599c501 100644 (file)
@@ -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);
+    }
 }
index acf6e01..339eebe 100644 (file)
@@ -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.