Skip to content

Commit

Permalink
feat: Adds resendfailedbatches setting to allow failed statements t…
Browse files Browse the repository at this point in the history
…o be retried. (#367 - Thanks @garemoko)
  • Loading branch information
garemoko authored and ryasmi committed Jan 8, 2019
1 parent 29d218c commit 803bb4c
Show file tree
Hide file tree
Showing 7 changed files with 41 additions and 5 deletions.
1 change: 1 addition & 0 deletions classes/log/store.php
Expand Up @@ -115,6 +115,7 @@ public function process_events(array $events) {
'lrs_username' => $this->get_config('username', ''),
'lrs_password' => $this->get_config('password', ''),
'lrs_max_batch_size' => $this->get_max_batch_size(),
'lrs_resend_failed_batches' => $this->get_config('resendfailedbatches', false),
],
];
$loadedevents = \src\handler($handlerconfig, $events);
Expand Down
17 changes: 16 additions & 1 deletion classes/task/emit_task.php
Expand Up @@ -41,6 +41,16 @@ private function get_failed_events($events) {
return $failedevents;
}

private function get_successful_events($events) {
$loadedevents = array_filter($events, function ($loadedevent) {
return $loadedevent['loaded'] === true;
});
$successfulevents = array_map(function ($loadedevent) {
return $loadedevent['event'];
}, $loadedevents);
return $successfulevents;
}

private function get_event_ids($loadedevents) {
return array_map(function ($loadedevent) {
return $loadedevent['event']->id;
Expand All @@ -61,13 +71,17 @@ private function delete_processed_events($events) {
global $DB;
$eventids = $this->get_event_ids($events);
$DB->delete_records_list('logstore_xapi_log', 'id', $eventids);
mtrace("Events (".implode(', ', $eventids).") have been successfully sent to LRS.");
}

private function store_failed_events($events) {
global $DB;
$failedevents = $this->get_failed_events($events);
$DB->insert_records('logstore_xapi_failed_log', $failedevents);
mtrace(count($failedevents) . " event(s) have failed to send to the LRS.");
}

private function record_successful_events($events) {
mtrace(count($this->get_successful_events($events)) . " event(s) have been successfully sent to the LRS.");
}

/**
Expand All @@ -81,6 +95,7 @@ public function execute() {
$extractedevents = $this->extract_events($store->get_max_batch_size());
$loadedevents = $store->process_events($extractedevents);
$this->store_failed_events($loadedevents);
$this->record_successful_events($loadedevents);
$this->delete_processed_events($loadedevents);
}
}
2 changes: 2 additions & 0 deletions lang/en/logstore_xapi.php
Expand Up @@ -49,3 +49,5 @@
$string['sendidnumber_desc'] = 'Statements will include the ID number (admin defined) for courses and activities in the object extensions';
$string['send_response_choices'] = 'Send response choices';
$string['send_response_choices_desc'] = 'Statements for multiple choice 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.';
4 changes: 4 additions & 0 deletions settings.php
Expand Up @@ -39,6 +39,10 @@
get_string('maxbatchsize', 'logstore_xapi'),
get_string('maxbatchsize_desc', 'logstore_xapi'), 30, PARAM_INT));

$settings->add(new admin_setting_configcheckbox('logstore_xapi/resendfailedbatches',
get_string('resendfailedbatches', 'logstore_xapi'),
get_string('resendfailedbatches_desc', 'logstore_xapi'), 0));

$settings->add(new admin_setting_configcheckbox('logstore_xapi/mbox',
get_string('mbox', 'logstore_xapi'),
get_string('mbox_desc', 'logstore_xapi'), 0));
Expand Down
2 changes: 1 addition & 1 deletion src/loader/lrs.php
Expand Up @@ -49,7 +49,7 @@ function load(array $config, array $events) {
curl_close($request);

if ($responsecode !== 200) {
throw new \Exception($responsetext);
throw new \Exception($responsetext, $responsecode);
}
};
return utils\load_in_batches($config, $events, $sendhttpstatements);
Expand Down
2 changes: 1 addition & 1 deletion src/loader/moodle_curl_lrs.php
Expand Up @@ -50,7 +50,7 @@ function load(array $config, array $events) {
$responsecode = $request->info['http_code'];

if ($responsecode !== 200) {
throw new \Exception($responsetext);
throw new \Exception($responsetext, $responsecode);
}
};
return utils\load_in_batches($config, $events, $sendhttpstatements);
Expand Down
18 changes: 16 additions & 2 deletions src/loader/utils/load_batch.php
Expand Up @@ -28,10 +28,24 @@ function load_batch(array $config, array $transformedevents, callable $loader) {
$loadedevents = construct_loaded_events($transformedevents, true);
return $loadedevents;
} catch (\Exception $e) {
$batchsize = count($transformedevents);
$logerror = $config['log_error'];
$logerror("Failed load for event id #" . $eventobj->id . ": " . $e->getMessage());
$logerror("Failed load batch (" . $batchsize . " events)" . $e->getMessage());
$logerror($e->getTraceAsString());
$loadedevents = construct_loaded_events($transformedevents, false);

// In the event of a 400 error, recursively retry sending statements in increasingly
// smaller batches so that only the actual bad data fails.
if ($batchsize === 1 || $e->getCode() !== 400 || $config['lrs_resend_failed_batches'] !== '1') {
$loadedevents = construct_loaded_events($transformedevents, false);
} else {
$newconfig = $config;
$newconfig['lrs_max_batch_size'] = round($batchsize / 2);
$batches = get_event_batches($newconfig, $transformedevents);
$loadedevents = array_reduce($batches, function ($result, $batch) use ($newconfig, $loader) {
$loadedbatchevents = load_batch($newconfig, $batch, $loader);
return array_merge($result, $loadedbatchevents);
}, []);
}
return $loadedevents;
}
}

0 comments on commit 803bb4c

Please sign in to comment.