MDL-67211 Tasks: Front-end to display currently running tasks.
authorMikhail Golenkov <mikhailgolenkov@catalyst-au.net>
Thu, 13 Aug 2020 07:44:13 +0000 (17:44 +1000)
committerMikhail Golenkov <mikhailgolenkov@catalyst-au.net>
Tue, 25 Aug 2020 07:00:46 +0000 (17:00 +1000)
Co-authored-by: Sam Marshall <s.marshall@open.ac.uk>
admin/tool/task/classes/running_tasks_table.php [new file with mode: 0644]
admin/tool/task/lang/en/tool_task.php
admin/tool/task/runningtasks.php [new file with mode: 0644]
admin/tool/task/settings.php
admin/tool/task/styles.css
admin/tool/task/tests/behat/running_tasks.feature [new file with mode: 0644]
admin/tool/task/tests/generator/behat_tool_task_generator.php [new file with mode: 0644]
admin/tool/task/tests/generator/lib.php [new file with mode: 0644]
admin/tool/task/version.php

diff --git a/admin/tool/task/classes/running_tasks_table.php b/admin/tool/task/classes/running_tasks_table.php
new file mode 100644 (file)
index 0000000..d08f458
--- /dev/null
@@ -0,0 +1,141 @@
+<?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/>.
+
+/**
+ * Running tasks table.
+ *
+ * @package    tool_task
+ * @copyright  2019 The Open University
+ * @copyright  2020 Mikhail Golenkov <golenkovm@gmail.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace tool_task;
+
+defined('MOODLE_INTERNAL') || die();
+
+require_once($CFG->libdir . '/tablelib.php');
+
+/**
+ * Table to display list of running task.
+ *
+ * @copyright  2019 The Open University
+ * @copyright  2020 Mikhail Golenkov <golenkovm@gmail.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class running_tasks_table extends \table_sql {
+
+    /**
+     * Constructor for the running tasks table.
+     */
+    public function __construct() {
+        parent::__construct('runningtasks');
+
+        $columnheaders = [
+            'classname'    => get_string('classname', 'tool_task'),
+            'type'         => get_string('tasktype', 'admin'),
+            'time'         => get_string('time'),
+            'timestarted'  => get_string('started', 'tool_task'),
+            'hostname'     => get_string('hostname', 'tool_task'),
+            'pid'          => get_string('pid', 'tool_task'),
+        ];
+        $this->define_columns(array_keys($columnheaders));
+        $this->define_headers(array_values($columnheaders));
+
+        // The name column is a header.
+        $this->define_header_column('classname');
+
+        // This table is not collapsible.
+        $this->collapsible(false);
+
+        // Allow pagination.
+        $this->pageable(true);
+    }
+
+    /**
+     * Query the db. Store results in the table object for use by build_table.
+     *
+     * @param int $pagesize size of page for paginated displayed table.
+     * @param bool $useinitialsbar do you want to use the initials bar. Bar
+     * will only be used if there is a fullname column defined for the table.
+     * @throws \dml_exception
+     */
+    public function query_db($pagesize, $useinitialsbar = true) {
+        $sort = $this->get_sql_sort();
+        $this->rawdata = \core\task\manager::get_running_tasks($sort);
+    }
+
+    /**
+     * Format the classname cell.
+     *
+     * @param   \stdClass $row
+     * @return  string
+     */
+    public function col_classname($row) : string {
+        $output = $row->classname;
+        if ($row->type == 'scheduled') {
+            if (class_exists($row->classname)) {
+                $task = new $row->classname;
+                if ($task instanceof \core\task\scheduled_task) {
+                    $output .= \html_writer::tag('div', $task->get_name(), ['class' => 'task-class']);
+                }
+            }
+        } else if ($row->type == 'adhoc') {
+            $output .= \html_writer::tag('div',
+                get_string('adhoctaskid', 'tool_task', $row->id), ['class' => 'task-class']);
+        }
+        return $output;
+    }
+
+    /**
+     * Format the type cell.
+     *
+     * @param   \stdClass $row
+     * @return  string
+     * @throws  \coding_exception
+     */
+    public function col_type($row) : string {
+        if ($row->type == 'scheduled') {
+            $output = \html_writer::span(get_string('scheduled', 'tool_task'), 'badge badge-primary');
+        } else if ($row->type == 'adhoc') {
+            $output = \html_writer::span(get_string('adhoc', 'tool_task'), 'badge badge-warning');
+        } else {
+            // This shouldn't ever happen.
+            $output = '';
+        }
+        return $output;
+    }
+
+    /**
+     * Format the time cell.
+     *
+     * @param   \stdClass $row
+     * @return  string
+     */
+    public function col_time($row) : string {
+        return format_time($row->time);
+    }
+
+    /**
+     * Format the timestarted cell.
+     *
+     * @param   \stdClass $row
+     * @return  string
+     */
+    public function col_timestarted($row) : string {
+        return userdate($row->timestarted);
+    }
+}
index 797f2f1..be26065 100644 (file)
@@ -22,6 +22,9 @@
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
+$string['adhoc'] = 'Ad-hoc';
+$string['adhoctaskid'] = 'Ad-hoc task id: {$a}';
+$string['adhoctasks'] = 'Ad-hoc tasks';
 $string['asap'] = 'ASAP';
 $string['adhocempty'] = 'Ad hoc task queue is empty';
 $string['adhocqueuesize'] = 'Ad hoc task queue has {$a} tasks';
@@ -32,6 +35,7 @@ $string['cannotfindthepathtothecli'] = 'Cannot find the path to the PHP CLI exec
 $string['checkadhocqueue'] = 'Ad hoc task queue';
 $string['checkcronrunning'] = 'Cron running';
 $string['checkmaxfaildelay'] = 'Tasks max fail delay';
+$string['classname'] = 'Class name';
 $string['clearfaildelay_confirm'] = 'Are you sure you want to clear the fail delay for task \'{$a}\'? After clearing the delay, the task will run according to its normal schedule.';
 $string['component'] = 'Component';
 $string['corecomponent'] = 'Core';
@@ -47,18 +51,22 @@ $string['faildelay'] = 'Fail delay';
 $string['fromcomponent'] = 'From component: {$a}';
 $string['hostname'] = 'Host name';
 $string['lastruntime'] = 'Last run';
+$string['lastupdated'] = 'Last updated {$a}.';
 $string['nextruntime'] = 'Next run';
 $string['pid'] = 'PID';
 $string['plugindisabled'] = 'Plugin disabled';
 $string['pluginname'] = 'Scheduled task configuration';
 $string['resettasktodefaults'] = 'Reset task schedule to defaults';
 $string['resettasktodefaults_help'] = 'This will discard any local changes and revert the schedule for this task back to its original settings.';
+$string['runningtasks'] = 'Tasks running now';
 $string['runnow'] = 'Run now';
 $string['runagain'] = 'Run again';
 $string['runnow_confirm'] = 'Are you sure you want to run this task \'{$a}\' now? The task will run on the web server and may take some time to complete.';
 $string['runpattern'] = 'Run pattern';
+$string['scheduled'] = 'Scheduled';
 $string['scheduledtasks'] = 'Scheduled tasks';
 $string['scheduledtaskchangesdisabled'] = 'Modifications to the list of scheduled tasks have been prevented in Moodle configuration';
+$string['started'] = 'Started';
 $string['taskdisabled'] = 'Task disabled';
 $string['taskfailures'] = '{$a} task(s) failing';
 $string['tasklogs'] = 'Task logs';
diff --git a/admin/tool/task/runningtasks.php b/admin/tool/task/runningtasks.php
new file mode 100644 (file)
index 0000000..d5c2842
--- /dev/null
@@ -0,0 +1,46 @@
+<?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/>.
+
+/**
+ * Running task admin page.
+ *
+ * @package    tool_task
+ * @copyright  2019 The Open University
+ * @copyright  2020 Mikhail Golenkov <golenkovm@gmail.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once(__DIR__ . '/../../../config.php');
+require_once($CFG->libdir.'/adminlib.php');
+require_once($CFG->libdir.'/tablelib.php');
+
+$pageurl = new \moodle_url('/admin/tool/task/runningtasks.php');
+$heading = get_string('runningtasks', 'tool_task');
+$PAGE->set_url($pageurl);
+$PAGE->set_context(context_system::instance());
+$PAGE->set_pagelayout('admin');
+$PAGE->set_title($heading);
+$PAGE->set_heading($heading);
+
+admin_externalpage_setup('runningtasks');
+
+echo $OUTPUT->header();
+
+$table = new \tool_task\running_tasks_table();
+$table->baseurl = $pageurl;
+$table->out(100, false);
+
+echo $OUTPUT->footer();
index ac9858e..3fd9669 100644 (file)
@@ -33,4 +33,13 @@ if ($hassiteconfig) {
             "$CFG->wwwroot/$CFG->admin/tool/task/scheduledtasks.php"
         )
     );
+
+    $ADMIN->add(
+        'taskconfig',
+        new admin_externalpage(
+            'runningtasks',
+            new lang_string('runningtasks', 'tool_task'),
+            "$CFG->wwwroot/$CFG->admin/tool/task/runningtasks.php"
+        )
+    );
 }
index 0e846ce..f297fd6 100644 (file)
@@ -1,4 +1,5 @@
-#page-admin-tool-task-scheduledtasks .task-class {
+#page-admin-tool-task-scheduledtasks .task-class,
+#page-admin-tool-task-runningtasks .task-class {
     display: block;
     padding: 0 0.5em;
     color: #888;
diff --git a/admin/tool/task/tests/behat/running_tasks.feature b/admin/tool/task/tests/behat/running_tasks.feature
new file mode 100644 (file)
index 0000000..e5db69c
--- /dev/null
@@ -0,0 +1,40 @@
+@tool @tool_task
+Feature: See running scheduled tasks
+  In order to configure scheduled tasks
+  As an admin
+  I need to see if tasks are running
+
+  Background:
+    Given I log in as "admin"
+
+  Scenario: If no task is running, I should see the corresponding message
+    Given I navigate to "Server > Tasks > Tasks running now" in site administration
+    Then I should see "Nothing to display"
+
+  Scenario: If tasks are running, I should see task details
+    Given the following "tool_task > scheduled tasks" exist:
+      | classname                            | seconds | hostname     | pid  |
+      | \core\task\automated_backup_task     | 121     | c69335460f7f | 1914 |
+    And the following "tool_task > adhoc tasks" exist:
+      | classname                            | seconds | hostname     | pid  |
+      | \core\task\asynchronous_backup_task  | 7201    | c69335460f7f | 1915 |
+      | \core\task\asynchronous_restore_task | 172800  | c69335460f7f | 1916 |
+    And I navigate to "Server > Tasks > Tasks running now" in site administration
+
+    # Check the scheduled task details.
+    Then I should see "Scheduled" in the "\core\task\automated_backup_task" "table_row"
+    And I should see "2 mins" in the "Automated backups" "table_row"
+    And I should see "c69335460f7f" in the "Automated backups" "table_row"
+    And I should see "1914" in the "Automated backups" "table_row"
+
+    # Check the "asynchronous_backup_task" adhoc task details.
+    And I should see "Ad-hoc" in the "\core\task\asynchronous_backup_task" "table_row"
+    And I should see "2 hours" in the "core\task\asynchronous_backup_task" "table_row"
+    And I should see "c69335460f7f" in the "core\task\asynchronous_backup_task" "table_row"
+    And I should see "1915" in the "core\task\asynchronous_backup_task" "table_row"
+
+    # Check the "asynchronous_restore_task" adhoc task details.
+    And I should see "Ad-hoc" in the "\core\task\asynchronous_restore_task" "table_row"
+    And I should see "2 days" in the "core\task\asynchronous_restore_task" "table_row"
+    And I should see "c69335460f7f" in the "core\task\asynchronous_restore_task" "table_row"
+    And I should see "1916" in the "core\task\asynchronous_restore_task" "table_row"
diff --git a/admin/tool/task/tests/generator/behat_tool_task_generator.php b/admin/tool/task/tests/generator/behat_tool_task_generator.php
new file mode 100644 (file)
index 0000000..307ad81
--- /dev/null
@@ -0,0 +1,57 @@
+<?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/>.
+
+/**
+ * Behat data generator for tool_task.
+ *
+ * @package   tool_task
+ * @category  test
+ * @copyright 2020 Mikhail Golenkov <golenkovm@gmail.com>
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Behat data generator for tool_task.
+ *
+ * @package   tool_task
+ * @category  test
+ * @copyright 2020 Mikhail Golenkov <golenkovm@gmail.com>
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class behat_tool_task_generator extends behat_generator_base {
+
+    /**
+     * Get a list of the entities that can be created.
+
+     * @return array entity name => information about how to generate.
+     */
+    protected function get_creatable_entities(): array {
+        return [
+            'scheduled tasks' => [
+                'singular' => 'scheduled task',
+                'datagenerator' => 'scheduled_tasks',
+                'required' => ['classname', 'seconds', 'hostname', 'pid'],
+            ],
+            'adhoc tasks' => [
+                'singular' => 'adhoc task',
+                'datagenerator' => 'adhoc_tasks',
+                'required' => ['classname', 'seconds', 'hostname', 'pid'],
+            ],
+        ];
+    }
+}
diff --git a/admin/tool/task/tests/generator/lib.php b/admin/tool/task/tests/generator/lib.php
new file mode 100644 (file)
index 0000000..b9324c5
--- /dev/null
@@ -0,0 +1,69 @@
+<?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/>.
+
+/**
+ * Tool task test data generator class
+ *
+ * @package tool_task
+ * @copyright 2020 Mikhail Golenkov <golenkovm@gmail.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Tool task test data generator class
+ *
+ * @package tool_task
+ * @copyright 2020 Mikhail Golenkov <golenkovm@gmail.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class tool_task_generator extends testing_module_generator {
+
+    /**
+     * Mark a scheduled task as running.
+     *
+     * @param array $data Scheduled task properties
+     * @throws dml_exception
+     */
+    public function create_scheduled_tasks($data) {
+        global $DB;
+        $conditions = ['classname' => $data['classname']];
+        $record = $DB->get_record('task_scheduled', $conditions, '*', MUST_EXIST);
+        $record->timestarted = time() - $data['seconds'];
+        $record->hostname = $data['hostname'];
+        $record->pid = $data['pid'];
+        $DB->update_record('task_scheduled', $record);
+    }
+
+    /**
+     * Mark an adhoc task as running.
+     *
+     * @param array $data Adhoc task properties
+     * @throws dml_exception
+     */
+    public function create_adhoc_tasks($data) {
+        global $DB;
+        $adhoctask = (object)[
+            'classname' => $data['classname'],
+            'nextruntime' => 0,
+            'timestarted' => time() - $data['seconds'],
+            'hostname' => $data['hostname'],
+            'pid' => $data['pid'],
+        ];
+        $DB->insert_record('task_adhoc', $adhoctask);
+    }
+}
index 636233a..40800e0 100644 (file)
@@ -24,7 +24,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2020061500; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2020061501; // The current plugin version (Date: YYYYMMDDXX)
 $plugin->requires  = 2020060900; // Requires this Moodle version
 $plugin->component = 'tool_task'; // Full name of the plugin (used for diagnostics)