Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions docs/apis/subsystems/output/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -488,15 +488,15 @@ class stored_progress_scheduled_task_example extends \core\task\scheduled_task {
for ($i = 1; $i <= $iterations; $i++) {

// Here we just update and tell it which one we are on and it will work out % from those.
$this->progress->update($i, $iterations, 'i am at ' . $i . ' of ' . $iterations);
$this->progress->update($i, $iterations, get_string('processingitem', 'mod_yourplugin', [
'current' => $i,
'total' => $iterations,
]));
sleep(1);

}

return true;

}

}

$task = new stored_progress_scheduled_task_example();
Expand All @@ -505,6 +505,8 @@ $task->initialise_stored_progress(); // Creates a stored progress record, so the

With the stored progress bars, you can update the progress either via iterations, by passing in the total amount expected and then the current iteration, using `->update()`(see: previous example), this will calculate the percentage complete for you. Or you can use `->update_full()` to manually set the percentage complete.

The web page polls for updates via the `core_output_poll_stored_progress` web service, at an interval controlled by the `$CFG->progresspollinterval` setting (in seconds, default `5`). A scheduled task, `\core\task\stored_progress_bar_cleanup_task`, runs daily to delete stored progress records with a `lastupdate` older than 24 hours.

## Reusing Output Classes in Web Services {/* #reusing-output-classes-in-web-services */}

<Since version="5.1" issueNumber="MDL-85509" />
Expand Down
80 changes: 80 additions & 0 deletions docs/apis/subsystems/task/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,86 @@ class my_task extends \core\task\scheduled_task {
}
```

### Reporting live progress {/* #reporting-live-progress */}

<Since version="4.5" issueNumber="MDL-70854" />

For long-running scheduled or adhoc tasks, you can report live progress by using the `\core\task\stored_progress_task_trait` trait. This stores the task's progress in the database, and allows it to be polled for and rendered as a progress bar on any page in Moodle (for example, on the [`admin/tool/task`](https://github.com/moodle/moodle/tree/main/public/admin/tool/task) "Tasks running now" page), via the `core_output_poll_stored_progress` web service.

```php
class my_task extends \core\task\scheduled_task {

use \core\task\stored_progress_task_trait;

public function execute() {

// This simulates a specific count of iterations the task will do, e.g. x number of courses to loop through and do something.
$iterations = 100;

// Updates the stored progress record with a start time.
$this->start_stored_progress();

for ($i = 1; $i <= $iterations; $i++) {

// Here we just update and tell it which one we are on, and it will work out the percentage from those.
$this->progress->update($i, $iterations, get_string('processingitem', 'mod_yourplugin', [
'current' => $i,
'total' => $iterations,
]));
}
}
}
```

Before the task has started running (for example, immediately after an adhoc task has been queued), you can call `initialise_stored_progress()` on the task instance to create the stored progress record in a "pending" state, so that it can be displayed on screen straight away. Note that an adhoc task has no database ID until it has been queued, so the task must be queued, and the returned ID set back on the task, before `initialise_stored_progress()` is called - otherwise its progress name won't match the one used when the task actually runs:

```php
$task = new my_adhoc_task();
$task->set_custom_data(['courseid' => $courseid]);

$taskid = \core\task\manager::queue_adhoc_task($task);
if ($taskid) {
// The task's ID must be set before initialising the stored progress record, so
// that both use the same idnumber when the task later calls start_stored_progress().
$task->set_id($taskid);

// Creates a stored progress record, so the progress can be displayed in a "pending" state, before the task has actually run.
$task->initialise_stored_progress();
}
```

#### Displaying the progress on a page {/* #displaying-the-progress-on-a-page */}

Once a task has created a stored progress record (either via `start_stored_progress()` or `initialise_stored_progress()`), any page can load it by its unique idnumber and render it. The idnumber is generated by `stored_progress_bar::convert_to_idnumber()`, using the task's class name and, for adhoc tasks, its record ID. This is exactly the approach used by the "Tasks running now" report in [`admin/tool/task`](https://github.com/moodle/moodle/blob/main/public/admin/tool/task/classes/running_tasks_table.php), which shows the live progress of every currently-running scheduled and adhoc task.

```php
if ($task instanceof \core\task\adhoc_task) {
// For an adhoc task, the idnumber includes the task's record ID, so that concurrent
// executions of the same adhoc task each have their own progress bar.
$idnumber = \core\output\stored_progress_bar::convert_to_idnumber(my_adhoc_task::class, $task->get_id());
} else {
// For a scheduled task, there is only ever one instance running at a time, so the
// idnumber is based on the class name alone.
$idnumber = \core\output\stored_progress_bar::convert_to_idnumber(my_task::class);
}

$bar = \core\output\stored_progress_bar::get_by_idnumber($idnumber);
if ($bar) {
// Renders the progress bar HTML, and queues up the `core/stored_progress` AMD
// module which polls the `core_output_poll_stored_progress` web service and
// updates the bar on screen until the task completes.
echo $bar->get_content();
} else {
// There is no stored progress record, e.g. because the task has not started, or
// has already finished and been cleaned up.
echo get_string('nothingtodisplay');
}
```

`get_content()` can be called from any page, at any time after the record has been created, including in a completely different request to the one that queued or ran the task - for example, an admin page which is refreshed and simply checks for the presence of a stored progress record matching a known idnumber.

See the [Stored Progress Bars](../output/index.md#stored-progress-bars) section of the Output API documentation for more information, including how to poll and render the progress bar, and how to configure the polling interval.

## For Administrators {/* #for-administrators */}

Several tools exist for administrators:
Expand Down
2 changes: 2 additions & 0 deletions versioned_docs/version-4.5/apis/subsystems/output/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,8 @@ class stored_progress_scheduled_task_example extends \core\task\scheduled_task {

With the stored progress bars, you can update the progress either via iterations, by passing in the total amount expected and then the current iteration, using `->update()`(see: previous example), this will calculate the percentage complete for you. Or you can use `->update_full()` to manually set the percentage complete.

The web page polls for updates via the `core_output_poll_stored_progress` web service, at an interval controlled by the `$CFG->progresspollinterval` setting (in seconds, default `5`). A scheduled task, `\core\task\stored_progress_bar_cleanup_task`, runs daily to delete stored progress records with a `lastupdate` older than 24 hours.

## See also {/* #see-also */}

- [HTML Guidelines](https://docs.moodle.org/dev/HTML_Guidelines)
Expand Down
63 changes: 63 additions & 0 deletions versioned_docs/version-4.5/apis/subsystems/task/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,69 @@ class my_task extends \core\task\scheduled_task {
}
```

### Reporting live progress {/* #reporting-live-progress */}

<Since version="4.5" issueNumber="MDL-70854" />

For long-running scheduled or adhoc tasks, you can report live progress by using the `\core\task\stored_progress_task_trait` trait. This stores the task's progress in the database, and allows it to be polled for and rendered as a progress bar on any page in Moodle (for example, on the [`admin/tool/task`](https://github.com/moodle/moodle/tree/MOODLE_405_STABLE/admin/tool/task) "Tasks running now" page), via the `core_output_poll_stored_progress` web service.

```php
class my_task extends \core\task\scheduled_task {

use \core\task\stored_progress_task_trait;

public function execute() {

// This simulates a specific count of iterations the task will do, e.g. x number of courses to loop through and do something.
$iterations = 100;

// This creates the stored progress record for the named task.
$this->start_stored_progress();

for ($i = 1; $i <= $iterations; $i++) {

// Here we just update and tell it which one we are on, and it will work out the percentage from those.
$this->progress->update($i, $iterations, get_string('processingitem', 'mod_yourplugin', [
'current' => $i,
'total' => $iterations,
]));
}
}
}
```

#### Displaying the progress on a page {/* #displaying-the-progress-on-a-page */}

Once a task has created a stored progress record (via `start_stored_progress()`), any page can load it by its unique idnumber and render it. The idnumber is generated by `stored_progress_bar::convert_to_idnumber()`, using the task's class name and, for adhoc tasks, its record ID. This is exactly the approach used by the "Tasks running now" report in [`admin/tool/task`](https://github.com/moodle/moodle/blob/MOODLE_405_STABLE/admin/tool/task/classes/running_tasks_table.php), which shows the live progress of every currently-running scheduled and adhoc task.

```php
if ($task instanceof \core\task\adhoc_task) {
// For an adhoc task, the idnumber includes the task's record ID, so that concurrent
// executions of the same adhoc task each have their own progress bar.
$idnumber = \core\output\stored_progress_bar::convert_to_idnumber(my_adhoc_task::class, $task->get_id());
} else {
// For a scheduled task, there is only ever one instance running at a time, so the
// idnumber is based on the class name alone.
$idnumber = \core\output\stored_progress_bar::convert_to_idnumber(my_task::class);
}

$bar = \core\output\stored_progress_bar::get_by_idnumber($idnumber);
if ($bar) {
// Renders the progress bar HTML, and queues up the `core/stored_progress` AMD
// module which polls the `core_output_poll_stored_progress` web service and
// updates the bar on screen until the task completes.
echo $bar->get_content();
} else {
// There is no stored progress record, e.g. because the task has not started, or
// has already finished and been cleaned up.
echo get_string('nothingtodisplay');
}
```

`get_content()` can be called from any page, at any time after the record has been created, including in a completely different request to the one that queued or ran the task - for example, an admin page which is refreshed and simply checks for the presence of a stored progress record matching a known idnumber.

See the [Stored Progress Bars](../output/index.md#stored-progress-bars) section of the Output API documentation for more information, including how to poll and render the progress bar, and how to configure the polling interval.

## For Administrators {/* #for-administrators */}

Several tools exist for administrators:
Expand Down
2 changes: 2 additions & 0 deletions versioned_docs/version-5.0/apis/subsystems/output/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,8 @@ $task->initialise_stored_progress(); // Creates a stored progress record, so the

With the stored progress bars, you can update the progress either via iterations, by passing in the total amount expected and then the current iteration, using `->update()`(see: previous example), this will calculate the percentage complete for you. Or you can use `->update_full()` to manually set the percentage complete.

The web page polls for updates via the `core_output_poll_stored_progress` web service, at an interval controlled by the `$CFG->progresspollinterval` setting (in seconds, default `5`). A scheduled task, `\core\task\stored_progress_bar_cleanup_task`, runs daily to delete stored progress records with a `lastupdate` older than 24 hours.

## See also {/* #see-also */}

- [HTML Guidelines](https://docs.moodle.org/dev/HTML_Guidelines)
Expand Down
80 changes: 80 additions & 0 deletions versioned_docs/version-5.0/apis/subsystems/task/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,86 @@ class my_task extends \core\task\scheduled_task {
}
```

### Reporting live progress {/* #reporting-live-progress */}

<Since version="4.5" issueNumber="MDL-70854" />

For long-running scheduled or adhoc tasks, you can report live progress by using the `\core\task\stored_progress_task_trait` trait. This stores the task's progress in the database, and allows it to be polled for and rendered as a progress bar on any page in Moodle (for example, on the [`admin/tool/task`](https://github.com/moodle/moodle/tree/MOODLE_500_STABLE/admin/tool/task) "Tasks running now" page), via the `core_output_poll_stored_progress` web service.

```php
class my_task extends \core\task\scheduled_task {

use \core\task\stored_progress_task_trait;

public function execute() {

// This simulates a specific count of iterations the task will do, e.g. x number of courses to loop through and do something.
$iterations = 100;

// Updates the stored progress record with a start time.
$this->start_stored_progress();

for ($i = 1; $i <= $iterations; $i++) {

// Here we just update and tell it which one we are on, and it will work out the percentage from those.
$this->progress->update($i, $iterations, get_string('processingitem', 'mod_yourplugin', [
'current' => $i,
'total' => $iterations,
]));
}
}
}
```

Before the task has started running (for example, immediately after an adhoc task has been queued), you can call `initialise_stored_progress()` on the task instance to create the stored progress record in a "pending" state, so that it can be displayed on screen straight away. Note that an adhoc task has no database ID until it has been queued, so the task must be queued, and the returned ID set back on the task, before `initialise_stored_progress()` is called - otherwise its progress name won't match the one used when the task actually runs:

```php
$task = new my_adhoc_task();
$task->set_custom_data(['courseid' => $courseid]);

$taskid = \core\task\manager::queue_adhoc_task($task);
if ($taskid) {
// The task's ID must be set before initialising the stored progress record, so
// that both use the same idnumber when the task later calls start_stored_progress().
$task->set_id($taskid);

// Creates a stored progress record, so the progress can be displayed in a "pending" state, before the task has actually run.
$task->initialise_stored_progress();
}
```

#### Displaying the progress on a page {/* #displaying-the-progress-on-a-page */}

Once a task has created a stored progress record (either via `start_stored_progress()` or `initialise_stored_progress()`), any page can load it by its unique idnumber and render it. The idnumber is generated by `stored_progress_bar::convert_to_idnumber()`, using the task's class name and, for adhoc tasks, its record ID. This is exactly the approach used by the "Tasks running now" report in [`admin/tool/task`](https://github.com/moodle/moodle/blob/MOODLE_500_STABLE/admin/tool/task/classes/running_tasks_table.php), which shows the live progress of every currently-running scheduled and adhoc task.

```php
if ($task instanceof \core\task\adhoc_task) {
// For an adhoc task, the idnumber includes the task's record ID, so that concurrent
// executions of the same adhoc task each have their own progress bar.
$idnumber = \core\output\stored_progress_bar::convert_to_idnumber(my_adhoc_task::class, $task->get_id());
} else {
// For a scheduled task, there is only ever one instance running at a time, so the
// idnumber is based on the class name alone.
$idnumber = \core\output\stored_progress_bar::convert_to_idnumber(my_task::class);
}

$bar = \core\output\stored_progress_bar::get_by_idnumber($idnumber);
if ($bar) {
// Renders the progress bar HTML, and queues up the `core/stored_progress` AMD
// module which polls the `core_output_poll_stored_progress` web service and
// updates the bar on screen until the task completes.
echo $bar->get_content();
} else {
// There is no stored progress record, e.g. because the task has not started, or
// has already finished and been cleaned up.
echo get_string('nothingtodisplay');
}
```

`get_content()` can be called from any page, at any time after the record has been created, including in a completely different request to the one that queued or ran the task - for example, an admin page which is refreshed and simply checks for the presence of a stored progress record matching a known idnumber.

See the [Stored Progress Bars](../output/index.md#stored-progress-bars) section of the Output API documentation for more information, including how to poll and render the progress bar, and how to configure the polling interval.

## For Administrators {/* #for-administrators */}

Several tools exist for administrators:
Expand Down
2 changes: 2 additions & 0 deletions versioned_docs/version-5.1/apis/subsystems/output/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,8 @@ $task->initialise_stored_progress(); // Creates a stored progress record, so the

With the stored progress bars, you can update the progress either via iterations, by passing in the total amount expected and then the current iteration, using `->update()`(see: previous example), this will calculate the percentage complete for you. Or you can use `->update_full()` to manually set the percentage complete.

The web page polls for updates via the `core_output_poll_stored_progress` web service, at an interval controlled by the `$CFG->progresspollinterval` setting (in seconds, default `5`). A scheduled task, `\core\task\stored_progress_bar_cleanup_task`, runs daily to delete stored progress records with a `lastupdate` older than 24 hours.

## Reusing Output Classes in Web Services {/* #reusing-output-classes-in-web-services */}

<Since version="5.1" issueNumber="MDL-85509" />
Expand Down
Loading
Loading