Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resend Adhoc task from CLI script #41

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
57 changes: 57 additions & 0 deletions classes/task/resend_task.php
Original file line number Diff line number Diff line change
@@ -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/>.

namespace logstore_xapi\task;

require_once($CFG->dirroot . '/admin/tool/log/store/xapi/lib.php');

/**
* Schedules a adhoc task resendadhoc.
*
* @package logstore_xapi
* @copyright Scott Verbeek <scottverbeek@catalyst-au.net>
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class resend_task extends \core\task\scheduled_task {

/**
* Get a descriptive name for this task (shown to admins).
*
* @return string
*/
public function get_name() {
return get_string('taskresend', 'logstore_xapi');
}

/**
* List a adhoc task that will resend the items.
*/
public function execute() {
global $DB;

$errortype = (string) get_config('logstore_xapi', 'resendtaskerrortype');
$eventname = (string) get_config('logstore_xapi', 'resendeventname');
$datefrom = (int) get_config('logstore_xapi', 'resenddatefrom');
$dateto = (int) get_config('logstore_xapi', 'resenddateto');
$runtime = (int) get_config('logstore_xapi', 'resendtaskruntime');
ScottVerbeek marked this conversation as resolved.
Show resolved Hide resolved
$batch = (int) get_config('logstore_xapi', 'resendbatch');

$task = \logstore_xapi\task\resendadhoc_task::instance($errortype, $eventname, $datefrom, $dateto, $runtime, $batch);
ScottVerbeek marked this conversation as resolved.
Show resolved Hide resolved
\core\task\manager::queue_adhoc_task($task);

mtrace("Queued a new adhoc task \logstore_xapi\task\resendadhoc_task with configuration ... " . $task->get_custom_data_as_string());
}
}
159 changes: 159 additions & 0 deletions classes/task/resendadhoc_task.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
<?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/>.

namespace logstore_xapi\task;

require_once($CFG->dirroot . '/admin/tool/log/store/xapi/lib.php');

/**
* Schedules a adhoc task resendadhoc.
*
* @package logstore_xapi
* @copyright Scott Verbeek <scottverbeek@catalyst-au.net>
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class resendadhoc_task extends \core\task\adhoc_task {

public static function instance(
ScottVerbeek marked this conversation as resolved.
Show resolved Hide resolved
string $errortype,
string $eventname,
int $datefrom,
int $dateto,
int $runtime,
int $batch
): self {
$task = new self();
$task->set_custom_data((object) [
'errortype' => $errortype,
'eventname' => $eventname,
'datefrom' => $datefrom,
'dateto' => $dateto,
'runtime' => $runtime,
'batch' => $batch
]);

return $task;
}

/**
* Do the job.
* Throw exceptions on errors (the job will be retried).
*/
public function execute() {
global $DB;

$options = $this->get_custom_data();

$basetable = XAPI_REPORT_SOURCE_FAILED;
$params = [];
$where = [];

// Start of sanitization, and applying of scope.
mtrace("Program will stop after {$options->runtime} seconds have passed, started at " .date('Y-m-d H:i:s T') . "...");
ScottVerbeek marked this conversation as resolved.
Show resolved Hide resolved
$starttime = microtime(true);

mtrace("Program will run in batches of {$options->batch} records ...");

if (!empty($options->errortype)) {
$options->errortype = explode(',', $options->errortype);
$options->errortype = array_map('intval', $options->errortype);
list($insql, $inparams) = $DB->get_in_or_equal($options->errortype, SQL_PARAMS_NAMED, 'errt');
$where[] = "x.errortype $insql";
$params = array_merge($params, $inparams);
mtrace('Applied scope for errortype ...');
}

if (!empty($options->eventname)) {
$options->eventname = explode(',', $options->eventname);
list($insql, $inparams) = $DB->get_in_or_equal($options->eventname, SQL_PARAMS_NAMED, 'evt');
$where[] = "x.eventname $insql";
$params = array_merge($params, $inparams);
mtrace('Applied scope for eventname ...');
}

if (!empty($options->datefrom) && $options->datefrom !== false) {
$where[] = 'x.timecreated >= :datefrom';
$params['datefrom'] = $options->datefrom;
mtrace('Applied scope for datefrom ...');
}

if (!empty($options->dateto) && $options->dateto !== false) {
$where[] = 'x.timecreated <= :dateto';
$params['dateto'] = $options->dateto;
mtrace('Applied scope for dateto ...');
}

if (!empty($options->datefrom) && !empty($options->dateto)) {
if ($options->datefrom > $options->dateto) {
mtrace(get_string('datetovalidation', 'logstore_xapi'));
exit(2);
}
}

if (empty($where)) {
$where[] = '1 = 1';
mtrace('No scope applied, moving all records ...');
}

$where = implode(' AND ', $where);

$sql = "SELECT x.id
FROM {{$basetable}} x
WHERE $where
ORDER BY x.id";

$limitfrom = 0;
$limitnum = $options->batch;
$counttotal = 0;
$countsucc = 0;
$countfail = 0;

do {
if (microtime(true) - $starttime >= $options->runtime) {
mtrace("Stopping the program, the maximum runtime has been exceeded ({$options->runtime} seconds).");
break; // Exit the loop after the specified runtime
}

mtrace("Reading at offset {$limitfrom} ...", ' ');
$records = $DB->get_records_sql($sql, $params, $limitfrom, $limitnum);
$count = count($records);
$counttotal += $count;
mtrace("read {$count} records.");

$eventids = array_keys($records);

if (empty($eventids)) {
break;
}

$mover = new \logstore_xapi\log\moveback($eventids, XAPI_REPORT_ID_ERROR);

if ($mover->execute()) {
$countsucc += $count;
mtrace("$count events successfully sent for reprocessing. Not increasing the offset (records were moved).");
} else {
$limitfrom += $count; // Increase the offset, when failed to move.
$countfail += $count;
mtrace("$count events failed to send for reprocessing. Increasing the offset by {$count} (records were not moved).");
}
} while ($count > 0);

mtrace("Total of {$counttotal} records matched the scope.");
mtrace("Total of {$countsucc} events successfully sent for reprocessing.");
mtrace("Total of {$countfail} events failed to send for reprocessing.");

}
}
9 changes: 9 additions & 0 deletions db/tasks.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@
'dayofweek' => '*',
'month' => '*'
),
array(
'classname' => '\logstore_xapi\task\resend_task',
'blocking' => 0,
'minute' => '0',
'hour' => '18',
'day' => '*',
'dayofweek' => '*',
'month' => '*'
),
array(
'classname' => '\logstore_xapi\task\sendfailednotifications_task',
'blocking' => 0,
Expand Down
15 changes: 15 additions & 0 deletions lang/en/logstore_xapi.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
$string['taskemit'] = 'Emit records to LRS';
$string['taskfailed'] = 'Emit failed records to LRS';
$string['taskhistorical'] = 'Emit historical records to LRS';
$string['taskresend'] = 'Move failed records to resend';
$string['tasksendfailednotifications'] = 'Send failed notifications';
$string['enablesendingnotifications'] = 'Send notifications?';
$string['enablesendingnotifications_desc'] = 'Control if notifications should be sent to configured recipients.';
Expand Down Expand Up @@ -89,6 +90,20 @@
$string['send_response_choices_desc'] = 'Statements for multiple choice and sequencing question answers will be sent to the LRS with the correct response and potential choices';
$string['resendfailedbatches'] = 'Resend failed batches';
$string['resendfailedbatches_desc'] = 'When processing events in batches, try re-sending events in smaller batches if a batch fails. If not selected, the whole batch will not be sent in the event of a failed event.';
$string['resendtask'] = 'Resend failed logs in background task';
$string['resendtask_help'] = 'The task resends failed logs in background. It will resend based upon the filter you may pass here.';
$string['resendtaskruntime'] = 'Runtime';
$string['resendtaskruntime_help'] = 'The maximum amount of time this program can run in seconds.';
$string['resendtaskerrortype'] = 'Error types';
$string['resendtaskerrortype_help'] = 'List of (comma seperated) error types (integer) to resend, empty means all.';
$string['resendeventname'] = 'Event names';
$string['resendeventname_help'] = 'List of (comma seperated) event names to resend.';
$string['resenddatefrom'] = 'Date from';
$string['resenddatefrom_help'] = 'Epoch from date to resend.';
$string['resenddateto'] = 'Date to';
$string['resenddateto_help'] = 'Epoch to date to resend.';
$string['resendbatch'] = 'Batch size';
$string['resendbatch_help'] = 'The batch size of each move iteration';
$string['type'] = 'Type';
$string['eventname'] = 'Event Name';
$string['username'] = 'Username';
Expand Down
52 changes: 50 additions & 2 deletions settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
$settings->add(new admin_setting_configcheckbox('logstore_xapi/mbox',
get_string('mbox', 'logstore_xapi'),
get_string('mbox_desc', 'logstore_xapi'), 0));

// optional hashing of email address
$settings->add(new admin_setting_configcheckbox('logstore_xapi/hashmbox',
get_string('hashmbox', 'logstore_xapi'),
Expand All @@ -86,7 +86,7 @@
$settings->add(new admin_setting_configcheckbox('logstore_xapi/send_username',
get_string('send_username', 'logstore_xapi'),
get_string('send_username_desc', 'logstore_xapi'), 0));

$settings->add(new admin_setting_configcheckbox('logstore_xapi/send_name',
get_string('send_name', 'logstore_xapi'),
get_string('send_name_desc', 'logstore_xapi'), 1));
Expand Down Expand Up @@ -154,6 +154,54 @@
$settings->add(new admin_setting_configmulticheckbox('logstore_xapi/routes',
get_string('routes', 'logstore_xapi'), '', $menuroutes, $menuroutes));

// Resend in background task.
$settings->add(new admin_setting_heading('resendtask',
get_string('resendtask', 'logstore_xapi'),
get_string('resendtask_help', 'logstore_xapi')));

$settings->add(new admin_setting_configduration('logstore_xapi/resendtaskruntime',
get_string('resendtaskruntime', 'logstore_xapi'),
get_string('resendtaskruntime_help', 'logstore_xapi'),
get_config('core', 'task_scheduled_max_runtime'),
PARAM_INT
));

$settings->add(new admin_setting_configtext('logstore_xapi/resendtaskerrortype',
get_string('resendtaskerrortype', 'logstore_xapi'),
get_string('resendtaskerrortype_help', 'logstore_xapi'),
'',
PARAM_TEXT
));

$settings->add(new admin_setting_configtextarea('logstore_xapi/resendeventname',
get_string('resendeventname', 'logstore_xapi'),
get_string('resendeventname_help', 'logstore_xapi'),
'',
PARAM_TEXT
));

$settings->add(new admin_setting_configtext('logstore_xapi/resenddatefrom',
get_string('resenddatefrom', 'logstore_xapi'),
get_string('resenddatefrom_help', 'logstore_xapi'),
'',
PARAM_INT
));

$settings->add(new admin_setting_configtext('logstore_xapi/resenddateto',
get_string('resenddateto', 'logstore_xapi'),
get_string('resenddateto_help', 'logstore_xapi'),
'',
PARAM_INT
));

$settings->add(new admin_setting_configtext('logstore_xapi/resendbatch',
get_string('resendbatch', 'logstore_xapi'),
get_string('resendbatch_help', 'logstore_xapi'),
12500,
PARAM_INT
));


$PAGE->requires->js_call_amd('logstore_xapi/settings', 'init');

// The xAPI Error Log page.
Expand Down
2 changes: 1 addition & 1 deletion version.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
defined('MOODLE_INTERNAL') || die();

$plugin->component = 'logstore_xapi';
$plugin->version = 2022101800;
$plugin->version = 2022101801;
$plugin->requires = 2020061500;
$plugin->supported = [39, 400];
$plugin->maturity = MATURITY_STABLE;
Expand Down
Loading